package test.metatype; import java.io.File; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Set; import javax.xml.xpath.XPathExpressionException; import org.osgi.service.component.annotations.Component; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.AttributeType; import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.osgi.service.metatype.annotations.Option; import aQute.bnd.annotation.metatype.Meta; import aQute.bnd.annotation.xml.XMLAttribute; import aQute.bnd.metatype.MetatypeVersion; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Resource; import aQute.bnd.test.XmlTester; import aQute.lib.io.IO; import junit.framework.TestCase; @SuppressWarnings({ "resource", "restriction" }) public class SpecMetatypeTest extends TestCase { public enum Foo { A, B } /** * Test method naming options with '.' and reserved names */ @ObjectClassDefinition public static interface Naming { String secret(); String _secret(); // .secret String __secret(); // _secret String $new(); // new String $$new(); // $new String a_b_c(); // a.b.c String a__b__c(); // a_b_c String _a__b(); // .a_b String $$$$$$$$a__b(); // $$$$a_b String $$$$$$$$a_b(); // $$$$a.b String a$(); // a String a$$(); // a$ String b$$$(); // b$ String a$$$$(); // a$$ String a$$_$$(); // a$.$ String a$$__$$(); // a$_$ String a_$_(); // a.. @AttributeDefinition(name = "secret") String xsecret(); @AttributeDefinition(name = ".secret") String x_secret(); @AttributeDefinition(name = "_secret") String x__secret(); // _secret @AttributeDefinition(name = "new") String x$new(); // new @AttributeDefinition(name = "$new") String x$$new(); // $new @AttributeDefinition(name = "a.b.c") String xa_b_c(); // a.b.c @AttributeDefinition(name = "a_b_c") String xa__b__c(); // a_b_c @AttributeDefinition(name = ".a_b") String x_a__b(); // .a_b @AttributeDefinition(name = "$$$$a_b") String x$$$$$$$$a__b(); // $$$$a_b @AttributeDefinition(name = "$$$$a.b") String x$$$$$$$$a_b(); // $$$$a.b @AttributeDefinition(name = "a") String xa$(); // a @AttributeDefinition(name = "a$") String xa$$(); // a$ @AttributeDefinition(name = "a$") String xb$$$(); // b$ @AttributeDefinition(name = "a$$") String xa$$$$(); // a$$ @AttributeDefinition(name = "a$.$") String xa$$_$$(); // a$.$ @AttributeDefinition(name = "a$_$") String xa$$__$$(); // a$_$ @AttributeDefinition(name = "a..") String xa_$_(); // a.. String noid(); @AttributeDefinition(name = "§NULL§") // Meta.NULL String nullid(); } private void assertAD(XmlTester xt, String id, String name) throws XPathExpressionException { assertAD(xt, id, name, null, null, null, 0, "String", null, null, null); } public void testNaming() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, Naming.class.getName()); b.build(); System.out.println(b.getErrors()); assertEquals(0, b.getErrors().size()); System.out.println(b.getWarnings()); assertEquals(0, b.getWarnings().size()); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$Naming.xml"); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); assertAD(xt, "secret", "Secret"); assertAD(xt, ".secret", "Secret"); assertAD(xt, "_secret", "Secret"); assertAD(xt, "new", "New"); assertAD(xt, "$new", "New"); assertAD(xt, "a.b.c", "A b c"); assertAD(xt, "a_b_c", "A b c"); assertAD(xt, ".a_b", "A b"); assertAD(xt, "$$$$a_b", "A b"); assertAD(xt, "$$$$a.b", "A b"); assertAD(xt, "a", "A "); assertAD(xt, "a$", "A "); assertAD(xt, "b$", "B "); assertAD(xt, "a$$", "A "); assertAD(xt, "a$.$", "A "); assertAD(xt, "a$_$", "A "); assertAD(xt, "a..", "A "); assertAD(xt, "xsecret", "secret"); assertAD(xt, "x.secret", ".secret"); assertAD(xt, "x_secret", "_secret"); assertAD(xt, "xnew", "new"); assertAD(xt, "x$new", "$new"); assertAD(xt, "xa.b.c", "a.b.c"); assertAD(xt, "xa_b_c", "a_b_c"); assertAD(xt, "x.a_b", ".a_b"); assertAD(xt, "x$$$$a_b", "$$$$a_b"); assertAD(xt, "x$$$$a.b", "$$$$a.b"); assertAD(xt, "xa", "a"); assertAD(xt, "xa$", "a$"); assertAD(xt, "xb$", "a$"); assertAD(xt, "xa$$", "a$$"); assertAD(xt, "xa$.$", "a$.$"); assertAD(xt, "xa$_$", "a$_$"); assertAD(xt, "xa..", "a.."); assertAD(xt, "noid", "Noid"); assertAD(xt, "nullid", "§NULL§"); } /** * Test method naming options with '.' and reserved names */ @ObjectClassDefinition public static @interface Naming14 { String PREFIX_ = "test."; String a$_$b() default "foo"; // test.a-b @AttributeDefinition(name = "a-b") String xa$_$b() default "foo"; // test.xa-b String value() default "foo"; // test.naming14 } private void assertAD(XmlTester xt, String id, String name, String deflt) throws XPathExpressionException { assertAD(xt, id, name, null, null, deflt, 0, "String", null, null, null); } public void testNaming14() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, Naming14.class.getName()); b.build(); System.out.println(b.getErrors()); assertEquals(0, b.getErrors().size()); System.out.println(b.getWarnings()); assertEquals(0, b.getWarnings().size()); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$Naming14.xml"); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester14(r); assertAD(xt, "test.a-b", "A b", "foo"); assertAD(xt, "test.xa-b", "a-b", "foo"); assertAD(xt, "test.naming14", "Value", "foo"); } @ObjectClassDefinition public static interface ADCollision { String a$$(); // a$ String a$$$(); // a$ } public void testADCollision() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, ADCollision.class.getName()); b.build(); System.out.println(b.getErrors()); assertEquals(1, b.getErrors().size()); } @ObjectClassDefinition(id = "duplicate") public static interface DupOCDId1 { } @ObjectClassDefinition(id = "duplicate") public static interface DupOCDId2 { } public void testOCDCollision() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); String name = DupOCDId2.class.getName(); b.setProperty(Constants.METATYPE_ANNOTATIONS, name.substring(0, name.length() - "1".length()) + "*"); b.build(); assertEquals(1, b.getErrors().size()); } @ObjectClassDefinition(pid = { "1" }) public static interface DupPid1 { } @ObjectClassDefinition(pid = { "1" }) public static interface DupPid2 { } @ObjectClassDefinition(factoryPid = { "2" }) public static interface DupPid3 { } @ObjectClassDefinition(factoryPid = { "2" }) public static interface DupPid4 { } @ObjectClassDefinition(pid = { "3" }, factoryPid = { "3" }) public static interface DupPid5 { } @ObjectClassDefinition(pid = { "4" }) public static interface DupPid6 { } @ObjectClassDefinition(factoryPid = { "4" }) public static interface DupPid7 { } public void testPidCollision() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); String name = DupPid2.class.getName(); b.setProperty(Constants.METATYPE_ANNOTATIONS, name.substring(0, name.length() - "1".length()) + "*"); b.build(); System.err.println(b.getErrors()); assertEquals(4, b.getErrors().size()); } /** * Test the special conversions. */ public static class MyList<T> extends ArrayList<T> { private static final long serialVersionUID = 1L; public MyList() {} } interface L<T> extends List<T> {} public static class StringList<T> implements L<T> { @Override public void add(int arg0, T arg1) { // TODO Auto-generated method stub } @Override public boolean addAll(int arg0, Collection< ? extends T> arg1) { // TODO Auto-generated method stub return false; } @Override public T get(int arg0) { // TODO Auto-generated method stub return null; } @Override public int indexOf(Object arg0) { // TODO Auto-generated method stub return 0; } @Override public int lastIndexOf(Object arg0) { // TODO Auto-generated method stub return 0; } @Override public ListIterator<T> listIterator() { // TODO Auto-generated method stub return null; } @Override public ListIterator<T> listIterator(int arg0) { // TODO Auto-generated method stub return null; } @Override public T remove(int arg0) { // TODO Auto-generated method stub return null; } @Override public T set(int arg0, T arg1) { // TODO Auto-generated method stub return null; } @Override public List<T> subList(int arg0, int arg1) { // TODO Auto-generated method stub return null; } @Override public boolean add(T arg0) { // TODO Auto-generated method stub return false; } @Override public boolean addAll(Collection< ? extends T> arg0) { // TODO Auto-generated method stub return false; } @Override public void clear() { // TODO Auto-generated method stub } @Override public boolean contains(Object arg0) { // TODO Auto-generated method stub return false; } @Override public boolean containsAll(Collection< ? > arg0) { // TODO Auto-generated method stub return false; } @Override public boolean isEmpty() { // TODO Auto-generated method stub return false; } @Override public Iterator<T> iterator() { // TODO Auto-generated method stub return null; } @Override public boolean remove(Object arg0) { // TODO Auto-generated method stub return false; } @Override public boolean removeAll(Collection< ? > arg0) { // TODO Auto-generated method stub return false; } @Override public boolean retainAll(Collection< ? > arg0) { // TODO Auto-generated method stub return false; } @Override public int size() { // TODO Auto-generated method stub return 0; } @Override public Object[] toArray() { // TODO Auto-generated method stub return null; } @Override @SuppressWarnings("hiding") public <T> T[] toArray(T[] arg0) { // TODO Auto-generated method stub return null; } } @ObjectClassDefinition static interface CollectionsTest { Collection<String> collection(); List<String> list(); Set<String> set(); // Queue<String> queue(); // Deque<String> deque(); // Stack<String> stack(); ArrayList<String> arrayList(); LinkedList<String> linkedList(); LinkedHashSet<String> linkedHashSet(); MyList<String> myList(); StringList<String> stringList(); } public void testCollections() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, CollectionsTest.class.getName()); b.build(); System.out.println(b.getErrors()); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources()); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$CollectionsTest.xml"); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='collection']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='list']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='set']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='arrayList']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='linkedList']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='linkedHashSet']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='myList']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='stringList']/@cardinality"); } /** * Test enum handling */ @ObjectClassDefinition public static interface Enums { enum X { requireConfiguration, optionalConfiguration, ignoreConfiguration } X r(); X i(); X o(); } private static final String[] optionLabels = { "requireConfiguration", "optionalConfiguration", "ignoreConfiguration" }; private static final String[] optionValues = optionLabels; private void assertAD(XmlTester xt, String id, String name, String[] optionLabels, String[] optionValues) throws XPathExpressionException { assertAD(xt, id, name, null, null, null, 0, "String", null, optionLabels, optionValues); } public void testEnum() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, Enums.class.getName() + "*"); b.build(); System.err.println(b.getErrors()); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$Enums.xml"); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); assertAD(xt, "r", "R", optionLabels, optionValues); assertAD(xt, "i", "I", optionLabels, optionValues); assertAD(xt, "o", "O", optionLabels, optionValues); } /** * Test the OCD settings */ @ObjectClassDefinition(pid = { "ocdEmptyPid" }) public static interface OCDEmpty {} @ObjectClassDefinition(description = "description", pid = { "ocdDescriptionPid" }) public static interface OCDDescription {} @ObjectClassDefinition(pid = { "ocdDesignatePidOnlyPid" }) public static interface OCDDesignatePidOnly {} @ObjectClassDefinition(factoryPid = { "ocdDesignatePidFactoryFactoryPid" }) public static interface OCDDesignatePidFactory {} @ObjectClassDefinition(id = "id", pid = { "ocdIdPid" }) public static interface OCDId {} @ObjectClassDefinition(id = "id2", pid = { "ocdId2Pid" }) public static interface OCDIdWithPid {} @ObjectClassDefinition(localization = "localization", pid = { "ocdLocalizationPid" }) public static interface OCDLocalization {} @ObjectClassDefinition(name = "name", pid = { "ocdNamePid" }) public static interface OCDName {} public void testOCD() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); String name = OCDEmpty.class.getName(); b.setProperty(Constants.METATYPE_ANNOTATIONS, name.substring(0, name.length() - "Empty".length()) + "*"); b.build(); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDEmpty", "test.metatype.SpecMetatypeTest$OCDEmpty", "Test metatype spec metatype test OCDEmpty", null, "ocdEmptyPid", false, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDName", "test.metatype.SpecMetatypeTest$OCDName", "name", null, "ocdNamePid", false, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDDescription", "test.metatype.SpecMetatypeTest$OCDDescription", "Test metatype spec metatype test OCDDescription", "description", "ocdDescriptionPid", false, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDDesignatePidOnly", "test.metatype.SpecMetatypeTest$OCDDesignatePidOnly", "Test metatype spec metatype test OCDDesignate pid only", null, "ocdDesignatePidOnlyPid", false, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDDesignatePidFactory", "test.metatype.SpecMetatypeTest$OCDDesignatePidFactory", "Test metatype spec metatype test OCDDesignate pid factory", null, "ocdDesignatePidFactoryFactoryPid", true, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDId", "id", "Id", // 5.2 // name // is // derived // from // id null, "ocdIdPid", false, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDIdWithPid", "id2", "Id2", null, "ocdId2Pid", false, null); assertOCD(b, "test.metatype.SpecMetatypeTest$OCDLocalization", "test.metatype.SpecMetatypeTest$OCDLocalization", "Test metatype spec metatype test OCDLocalization", null, "ocdLocalizationPid", false, "localization"); } private void assertOCD(Builder b, String cname, String id, String name, String description, String designate, boolean factory, String localization) throws Exception { Resource r = b.getJar().getResource("OSGI-INF/metatype/" + id + ".xml"); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester13(r); xt.assertExactAttribute(id, "metatype:MetaData/OCD/@id"); xt.assertExactAttribute(name, "metatype:MetaData/OCD/@name"); String expected = localization == null ? "OSGI-INF/I10n/" + cname : localization; xt.assertExactAttribute(localization == null ? "OSGI-INF/l10n/" + cname : localization, "metatype:MetaData/@localization"); xt.assertExactAttribute(description == null ? "" : description, "metatype:MetaData/OCD/@description"); if (designate != null) { if (factory) xt.assertExactAttribute(designate, "metatype:MetaData/Designate/@factoryPid"); else xt.assertExactAttribute(designate, "metatype:MetaData/Designate/@pid"); } xt.assertExactAttribute(id, "metatype:MetaData/Designate/Object/@ocdref"); } /** * Test the AD settings. */ @ObjectClassDefinition(description = "advariations") public static interface TestAD { @AttributeDefinition String noSettings(); @AttributeDefinition(name = "id") String withId(); @AttributeDefinition(name = "name") String withName(); @AttributeDefinition(max = "1") String withMax(); @AttributeDefinition(min = "-1") String withMin(); @AttributeDefinition(defaultValue = { "deflt" }) String withDefault(); @AttributeDefinition(cardinality = 0) String[] withC0(); @AttributeDefinition(cardinality = 1) String[] withC1(); @AttributeDefinition(cardinality = -1) Collection<String> withC_1(); @AttributeDefinition(cardinality = -1) String[] withC_1ButArray(); @AttributeDefinition(cardinality = 1) Collection<String> withC1ButCollection(); @AttributeDefinition(type = AttributeType.STRING) int withInt(); @AttributeDefinition(type = AttributeType.INTEGER) String withString(); @AttributeDefinition(description = "description_xxx\"xxx'xxx") String a(); @AttributeDefinition(options = { @Option(label = "a", value = "a"), @Option(label = "b", value = "b") }) String valuesOnly(); @AttributeDefinition(options = { @Option(label = "a", value = "A"), @Option(label = "b", value = "B") }) String labelsAndValues(); @AttributeDefinition(required = true) String required(); @AttributeDefinition(required = false) String notRequired(); } public void testAD() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, TestAD.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$TestAD.xml"); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); assertAD(xt, "noSettings", "No settings", null, null, null, 0, "String", null, null, null); assertAD(xt, "withId", "id", null, null, null, 0, "String", null, null, null); assertAD(xt, "withName", "name", null, null, null, 0, "String", null, null, null); assertAD(xt, "withMax", "With max", null, "1", null, 0, "String", null, null, null); assertAD(xt, "withMin", "With min", "-1", null, null, 0, "String", null, null, null); assertAD(xt, "withC1", "With c1", null, null, null, 1, "String", null, null, null); assertAD(xt, "withC0", "With c0", null, null, null, 0, "String", null, null, null); assertAD(xt, "withC.1", "With c 1", null, null, null, -1, "String", null, null, null); assertAD(xt, "withC.1ButArray", "With c 1 but array", null, null, null, -1, "String", null, null, null); assertAD(xt, "withC1ButCollection", "With c1 but collection", null, null, null, 1, "String", null, null, null); assertAD(xt, "withInt", "With int", null, null, null, 0, "String", null, null, null); assertAD(xt, "withString", "With string", null, null, null, 0, "Integer", null, null, null); assertAD(xt, "a", "A", null, null, null, 0, "String", "description_xxx\"xxx'xxx", null, null); assertAD(xt, "valuesOnly", "Values only", null, null, null, 0, "String", null, new String[] { "a", "b" }, new String[] { "a", "b" }); assertAD(xt, "labelsAndValues", "Labels and values", null, null, null, 0, "String", null, new String[] { "a", "b" }, new String[] { "A", "B" }); } private XmlTester xmlTester12(Resource r) throws Exception { return xmlTester(r, MetatypeVersion.VERSION_1_2); } private XmlTester xmlTester13(Resource r) throws Exception { return xmlTester(r, MetatypeVersion.VERSION_1_3); } private XmlTester xmlTester14(Resource r) throws Exception { return xmlTester(r, MetatypeVersion.VERSION_1_4); } private XmlTester xmlTester(Resource r, MetatypeVersion version) throws Exception { XmlTester xt = new XmlTester(r.openInputStream(), "metatype", version.getNamespace()); xt.assertNamespace(version.getNamespace()); return xt; } /** * Test the AD inheritance. */ @ObjectClassDefinition(description = "adinheritance-super-one") public static interface TestADWithInheritanceSuperOne { @AttributeDefinition String fromSuperOne(); } @ObjectClassDefinition(description = "adinheritance-super") public static interface TestADWithInheritanceSuperTwo { @AttributeDefinition String fromSuperTwo(); } @ObjectClassDefinition(description = "adinheritance-child") public static interface TestADWithInheritanceChild extends TestADWithInheritanceSuperOne, TestADWithInheritanceSuperTwo { @AttributeDefinition String fromChild(); } public void testADWithInheritance() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, TestADWithInheritanceChild.class.getName().substring(0, TestADWithInheritanceChild.class.getName().length() - "Child".length()) + "*"); // b.setProperty("-metatypeannotations-inherit", "true"); b.build(); Resource r = b.getJar() .getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$TestADWithInheritanceChild.xml"); System.err.println(b.getErrors()); assertEquals(0, b.getErrors().size()); System.err.println(b.getWarnings()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); assertAD(xt, "fromChild", "From child", null, null, null, 0, "String", null, null, null); assertAD(xt, "fromSuperOne", "From super one", null, null, null, 0, "String", null, null, null); assertAD(xt, "fromSuperTwo", "From super two", null, null, null, 0, "String", null, null, null); } @SuppressWarnings("null") private void assertAD(XmlTester xt, String id, String name, String min, String max, String deflt, int cardinality, String type, String description, String[] optionLabels, String[] optionValues) throws XPathExpressionException { xt.assertExactAttribute(name, "metatype:MetaData/OCD/AD[@id='" + id + "']/@name"); xt.assertExactAttribute(id, "metatype:MetaData/OCD/AD[@id='" + id + "']/@id"); xt.assertExactAttribute(min == null ? "" : min, "metatype:MetaData/OCD/AD[@id='" + id + "']/@min"); xt.assertExactAttribute(max == null ? "" : max, "metatype:MetaData/OCD/AD[@id='" + id + "']/@max"); xt.assertExactAttribute(deflt == null ? "" : deflt, "metatype:MetaData/OCD/AD[@id='" + id + "']/@default"); if (cardinality == 0) { xt.assertExactAttribute("", "metatype:MetaData/OCD/AD[@id='" + id + "']/@cardinality"); } else { xt.assertExactAttribute(cardinality + "", "metatype:MetaData/OCD/AD[@id='" + id + "']/@cardinality"); } xt.assertExactAttribute(type, "metatype:MetaData/OCD/AD[@id='" + id + "']/@type"); xt.assertExactAttribute(description == null ? "" : description, "metatype:MetaData/OCD/AD[@id='" + id + "']/@description"); assertEquals(optionLabels == null, optionValues == null); if (optionLabels != null) { assertEquals(optionLabels.length, optionValues.length); // option count is correct xt.assertNumber(Double.valueOf(optionLabels.length), "count(metatype:MetaData/OCD/AD[@id='" + id + "']/Option)"); for (int i = 0; i < optionLabels.length; i++) { String expr = "metatype:MetaData/OCD/AD[@id='" + id + "']/Option[@label='" + optionLabels[i] + "']/@value"; xt.assertExactAttribute(optionValues[i], expr); } } } /** * Test all the return types. */ @ObjectClassDefinition(description = "simple", name = "TestSimple") public static interface TestReturnTypes { boolean rpBoolean(); byte rpByte(); char rpCharacter(); short rpShort(); int rpInt(); long rpLong(); float rpFloat(); double rpDouble(); Boolean rBoolean(); Byte rByte(); Character rCharacter(); Short rShort(); Integer rInt(); Long rLong(); Float rFloat(); Double rDouble(); String rString(); URI rURI(); boolean[] rpaBoolean(); byte[] rpaByte(); char[] rpaCharacter(); short[] rpaShort(); int[] rpaInt(); long[] rpaLong(); float[] rpaFloat(); double[] rpaDouble(); Collection<Boolean> rBooleans(); Collection<Byte> rBytes(); Collection<Character> rCharacters(); Collection<Short> rShorts(); Collection<Integer> rInts(); Collection<Long> rLongs(); Collection<Float> rFloats(); Collection<Double> rDoubles(); Collection<String> rStrings(); Collection<URI> rURIs(); Boolean[] raBoolean(); Byte[] raByte(); Character[] raCharacter(); Short[] raShort(); Integer[] raInt(); Long[] raLong(); Float[] raFloat(); Double[] raDouble(); String[] raString(); URI[] raURI(); } public void testReturnTypes() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, TestReturnTypes.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$TestReturnTypes.xml"); System.err.println(b.getErrors()); assertEquals(0, b.getErrors().size()); System.err.println(b.getWarnings()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); // Primitives xt.assertExactAttribute("Boolean", "metatype:MetaData/OCD/AD[@id='rpBoolean']/@type"); xt.assertExactAttribute("Byte", "metatype:MetaData/OCD/AD[@id='rpByte']/@type"); xt.assertExactAttribute("Char", "metatype:MetaData/OCD/AD[@id='rpCharacter']/@type"); xt.assertExactAttribute("Short", "metatype:MetaData/OCD/AD[@id='rpShort']/@type"); xt.assertExactAttribute("Integer", "metatype:MetaData/OCD/AD[@id='rpInt']/@type"); xt.assertExactAttribute("Long", "metatype:MetaData/OCD/AD[@id='rpLong']/@type"); xt.assertExactAttribute("Float", "metatype:MetaData/OCD/AD[@id='rpFloat']/@type"); xt.assertExactAttribute("Double", "metatype:MetaData/OCD/AD[@id='rpDouble']/@type"); // Primitive Wrappers xt.assertExactAttribute("Boolean", "metatype:MetaData/OCD/AD[@id='rBoolean']/@type"); xt.assertExactAttribute("Byte", "metatype:MetaData/OCD/AD[@id='rByte']/@type"); xt.assertExactAttribute("Char", "metatype:MetaData/OCD/AD[@id='rCharacter']/@type"); xt.assertExactAttribute("Short", "metatype:MetaData/OCD/AD[@id='rShort']/@type"); xt.assertExactAttribute("Integer", "metatype:MetaData/OCD/AD[@id='rInt']/@type"); xt.assertExactAttribute("Long", "metatype:MetaData/OCD/AD[@id='rLong']/@type"); xt.assertExactAttribute("Float", "metatype:MetaData/OCD/AD[@id='rFloat']/@type"); xt.assertExactAttribute("Double", "metatype:MetaData/OCD/AD[@id='rDouble']/@type"); // Primitive Arrays xt.assertExactAttribute("Boolean", "metatype:MetaData/OCD/AD[@id='rpaBoolean']/@type"); xt.assertExactAttribute("Byte", "metatype:MetaData/OCD/AD[@id='rpaByte']/@type"); xt.assertExactAttribute("Char", "metatype:MetaData/OCD/AD[@id='rpaCharacter']/@type"); xt.assertExactAttribute("Short", "metatype:MetaData/OCD/AD[@id='rpaShort']/@type"); xt.assertExactAttribute("Integer", "metatype:MetaData/OCD/AD[@id='rpaInt']/@type"); xt.assertExactAttribute("Long", "metatype:MetaData/OCD/AD[@id='rpaLong']/@type"); xt.assertExactAttribute("Float", "metatype:MetaData/OCD/AD[@id='rpaFloat']/@type"); xt.assertExactAttribute("Double", "metatype:MetaData/OCD/AD[@id='rpaDouble']/@type"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaBoolean']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaByte']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaCharacter']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaShort']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaInt']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaLong']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaFloat']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='rpaDouble']/@cardinality"); // Wrapper + Object arrays xt.assertExactAttribute("Boolean", "metatype:MetaData/OCD/AD[@id='raBoolean']/@type"); xt.assertExactAttribute("Byte", "metatype:MetaData/OCD/AD[@id='raByte']/@type"); xt.assertExactAttribute("Char", "metatype:MetaData/OCD/AD[@id='raCharacter']/@type"); xt.assertExactAttribute("Short", "metatype:MetaData/OCD/AD[@id='raShort']/@type"); xt.assertExactAttribute("Integer", "metatype:MetaData/OCD/AD[@id='raInt']/@type"); xt.assertExactAttribute("Long", "metatype:MetaData/OCD/AD[@id='raLong']/@type"); xt.assertExactAttribute("Float", "metatype:MetaData/OCD/AD[@id='raFloat']/@type"); xt.assertExactAttribute("Double", "metatype:MetaData/OCD/AD[@id='raDouble']/@type"); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='raString']/@type"); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='raURI']/@type"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raBoolean']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raByte']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raCharacter']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raShort']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raInt']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raLong']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raFloat']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raDouble']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raString']/@cardinality"); xt.assertExactAttribute("2147483647", "metatype:MetaData/OCD/AD[@id='raURI']/@cardinality"); // Wrapper + Object collections xt.assertExactAttribute("Boolean", "metatype:MetaData/OCD/AD[@id='rBooleans']/@type"); xt.assertExactAttribute("Byte", "metatype:MetaData/OCD/AD[@id='rBytes']/@type"); xt.assertExactAttribute("Char", "metatype:MetaData/OCD/AD[@id='rCharacter']/@type"); xt.assertExactAttribute("Short", "metatype:MetaData/OCD/AD[@id='rShorts']/@type"); xt.assertExactAttribute("Integer", "metatype:MetaData/OCD/AD[@id='rInts']/@type"); xt.assertExactAttribute("Long", "metatype:MetaData/OCD/AD[@id='rLongs']/@type"); xt.assertExactAttribute("Float", "metatype:MetaData/OCD/AD[@id='rFloats']/@type"); xt.assertExactAttribute("Double", "metatype:MetaData/OCD/AD[@id='rDoubles']/@type"); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='rStrings']/@type"); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='rURIs']/@type"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rBooleans']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rBytes']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rCharacters']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rShorts']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rInts']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rLongs']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rFloats']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rDoubles']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rStrings']/@cardinality"); xt.assertExactAttribute("-2147483648", "metatype:MetaData/OCD/AD[@id='rURIs']/@cardinality"); } /** * Test simple * * @author aqute */ @ObjectClassDefinition(description = "simple", name = "TestSimple", pid = { "simplePid", "$" }) public static interface TestSimple { @AttributeDefinition String simple(); String[] notSoSimple(); Collection<String> stringCollection(); @AttributeDefinition(defaultValue = { "true" }, required = false) boolean enabled(); } public void testSimple() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, TestSimple.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$TestSimple.xml"); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); testSimple(b, xt); } public void testSimple13() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, TestSimple.class.getName()); b.setProperty(Constants.METATYPE_ANNOTATIONS_OPTIONS, "version;minimum=1.3.0"); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$TestSimple.xml"); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester13(r); testSimple(b, xt); } private void testSimple(Builder b, XmlTester xt) throws XPathExpressionException { assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); for (String res : b.getJar().getResources().keySet()) { if (res.endsWith(".xml")) System.err.println(res); } xt.assertExactAttribute("TestSimple", "metatype:MetaData/OCD/@name"); xt.assertExactAttribute("simple", "metatype:MetaData/OCD/@description"); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$TestSimple", "metatype:MetaData/OCD/@id"); xt.assertExactAttribute("simplePid", "metatype:MetaData/Designate[1]/@pid"); xt.assertExactAttribute(TestSimple.class.getName(), "metatype:MetaData/Designate[2]/@pid"); xt.assertExactAttribute(TestSimple.class.getName(), "metatype:MetaData/Designate/Object/@ocdref"); xt.assertExactAttribute("simple", "metatype:MetaData/OCD/AD[@id='simple']/@id"); xt.assertExactAttribute("Simple", "metatype:MetaData/OCD/AD[@id='simple']/@name"); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='simple']/@type"); xt.assertExactAttribute("false", "metatype:MetaData/OCD/AD[@id='enabled']/@required"); xt.assertExactAttribute("true", "metatype:MetaData/OCD/AD[@id='enabled']/@default"); xt.assertExactAttribute(Integer.MAX_VALUE + "", "metatype:MetaData/OCD/AD[@id='notSoSimple']/@cardinality"); } @ObjectClassDefinition public static @interface AnnotationDefaults { int integer() default 1; int[] integers() default { 2, 3 }; boolean bool() default true; boolean[] bools() default { true, false }; Class< ? > clazz() default String.class; Class< ? >[] clazzs() default { Integer.class, Double.class }; enum L { A, B, C } L l() default L.A; L[] ls() default { L.B, L.C }; String string() default "foo"; String[] strings() default { "bar", "baz" }; } public void testAnnotationDefaults() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, AnnotationDefaults.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$AnnotationDefaults.xml"); System.err.println(b.getErrors()); assertEquals(0, b.getErrors().size()); System.err.println(b.getWarnings()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); xt.assertExactAttribute("1", "metatype:MetaData/OCD/AD[@id='integer']/@default"); xt.assertExactAttribute("2,3", "metatype:MetaData/OCD/AD[@id='integers']/@default"); xt.assertExactAttribute("true", "metatype:MetaData/OCD/AD[@id='bool']/@default"); xt.assertExactAttribute("true,false", "metatype:MetaData/OCD/AD[@id='bools']/@default"); xt.assertExactAttribute(String.class.getName(), "metatype:MetaData/OCD/AD[@id='clazz']/@default"); xt.assertExactAttribute(Integer.class.getName() + "," + Double.class.getName(), "metatype:MetaData/OCD/AD[@id='clazzs']/@default"); xt.assertExactAttribute("A", "metatype:MetaData/OCD/AD[@id='l']/@default"); xt.assertExactAttribute("B,C", "metatype:MetaData/OCD/AD[@id='ls']/@default"); xt.assertExactAttribute("foo", "metatype:MetaData/OCD/AD[@id='string']/@default"); xt.assertExactAttribute("bar,baz", "metatype:MetaData/OCD/AD[@id='strings']/@default"); } @ObjectClassDefinition public static abstract class Abstract { } public void testAbstract() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, Abstract.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$Abstract.xml"); assertEquals(1, b.getErrors().size()); assertNull(r); } @ObjectClassDefinition public static @interface NestedInner { } @ObjectClassDefinition public static @interface NestedOuter { NestedInner inner(); } public void testNested() throws Exception { { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, NestedInner.class.getName() + "," + NestedOuter.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$NestedOuter.xml"); assertEquals(1, b.getErrors().size()); } { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, NestedInner.class.getName() + "," + NestedOuter.class.getName()); b.setProperty(Constants.METATYPE_ANNOTATIONS_OPTIONS, "nested"); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$NestedOuter.xml"); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='inner']/@type"); } } @ObjectClassDefinition public static @interface DesignateOCD { } @Component(configurationPid = "simplePid") @Designate(ocd = DesignateOCD.class, factory = true) public static class DesignateComponent {} @Component(name = "simplePidName") @Designate(ocd = DesignateOCD.class, factory = true) public static class DesignateComponent2 {} @Component @Designate(ocd = DesignateOCD.class, factory = true) public static class DesignateComponent3 {} @Component(configurationPid = "$") @Designate(ocd = DesignateOCD.class, factory = true) public static class DesignateComponent4 {} public void testDesignate() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, "test.metatype.SpecMetatypeTest$Designate*"); b.setProperty(Constants.DSANNOTATIONS, "test.metatype.SpecMetatypeTest$Designate*"); b.build(); { Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$DesignateOCD.xml"); assertEquals(b.getErrors().toString(), 0, b.getErrors().size()); assertEquals(b.getWarnings().toString(), 0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester13(r); xt.assertExactAttribute("Test metatype spec metatype test designate OCD", "metatype:MetaData/OCD/@name"); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$DesignateOCD", "metatype:MetaData/OCD/@id"); xt.assertExactAttribute("simplePid", "metatype:MetaData/Designate[1]/@factoryPid"); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$DesignateOCD", "metatype:MetaData/Designate[1]/Object/@ocdref"); xt.assertExactAttribute("simplePidName", "metatype:MetaData/Designate[2]/@factoryPid"); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$DesignateOCD", "metatype:MetaData/Designate[2]/Object/@ocdref"); xt.assertExactAttribute(DesignateComponent3.class.getName(), "metatype:MetaData/Designate[3]/@factoryPid"); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$DesignateOCD", "metatype:MetaData/Designate[3]/Object/@ocdref"); xt.assertExactAttribute(DesignateComponent4.class.getName(), "metatype:MetaData/Designate[4]/@factoryPid"); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$DesignateOCD", "metatype:MetaData/Designate[4]/Object/@ocdref"); } } @XMLAttribute(namespace = "org.foo.extensions.v1", prefix = "foo", embedIn = "*") @Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) @interface OCDTestExtensions { boolean booleanAttr() default true; String stringAttr(); Foo fooAttr(); String[] stringArrayAttr(); int[] intArrayAttr(); } @XMLAttribute(namespace = "org.foo.extensions.v1", prefix = "foo", embedIn = "*") @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) @interface ADTestExtensions { boolean booleanAttr2() default true; String stringAttr2(); Foo fooAttr2(); Class< ? > classAttr2() default Object.class; } @ObjectClassDefinition @OCDTestExtensions(stringAttr = "ocd", fooAttr = Foo.A, stringArrayAttr = { "foo", "bar" }, intArrayAttr = { 1, 2, 3 }) public static interface TestExtensions { @AttributeDefinition String simple(); @ADTestExtensions(stringAttr2 = "ad", fooAttr2 = Foo.B, classAttr2 = String.class) String[] notSoSimple(); Collection<String> stringCollection(); @ADTestExtensions(stringAttr2 = "ad2", fooAttr2 = Foo.A) @AttributeDefinition(defaultValue = { "true" }, required = false) boolean enabled(); } public void testExtensions() throws Exception { MetatypeVersion version = MetatypeVersion.VERSION_1_2; Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, TestExtensions.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$TestExtensions.xml"); assertEquals(0, b.getErrors().size()); assertEquals("warnings: " + b.getWarnings(), 0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = new XmlTester(r.openInputStream(), "metatype", version.getNamespace(), "foo", "org.foo.extensions.v1"); xt.assertNamespace(version.getNamespace()); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$TestExtensions", "metatype:MetaData/OCD/@id"); xt.assertExactAttribute("simple", "metatype:MetaData/OCD/AD[@id='simple']/@id"); xt.assertExactAttribute("Simple", "metatype:MetaData/OCD/AD[@id='simple']/@name"); xt.assertExactAttribute("String", "metatype:MetaData/OCD/AD[@id='simple']/@type"); xt.assertExactAttribute("false", "metatype:MetaData/OCD/AD[@id='enabled']/@required"); xt.assertExactAttribute("true", "metatype:MetaData/OCD/AD[@id='enabled']/@default"); xt.assertExactAttribute(Integer.MAX_VALUE + "", "metatype:MetaData/OCD/AD[@id='notSoSimple']/@cardinality"); xt.assertCount(8, "metatype:MetaData/OCD/@*"); xt.assertExactAttribute("ocd", "metatype:MetaData/OCD/@foo:stringAttr"); xt.assertExactAttribute("A", "metatype:MetaData/OCD/@foo:fooAttr"); xt.assertExactAttribute("foo bar", "metatype:MetaData/OCD/@foo:stringArrayAttr"); xt.assertExactAttribute("1 2 3", "metatype:MetaData/OCD/@foo:intArrayAttr"); xt.assertExactAttribute("true", "metatype:MetaData/OCD/@foo:booleanAttr"); xt.assertCount(3, "metatype:MetaData/OCD/AD[@id='simple']/@*"); xt.assertCount(8, "metatype:MetaData/OCD/AD[@id='notSoSimple']/@*"); xt.assertExactAttribute("ad", "metatype:MetaData/OCD/AD[@id='notSoSimple']/@foo:stringAttr2"); xt.assertExactAttribute("B", "metatype:MetaData/OCD/AD[@id='notSoSimple']/@foo:fooAttr2"); xt.assertExactAttribute(String.class.getName(), "metatype:MetaData/OCD/AD[@id='notSoSimple']/@foo:classAttr2"); xt.assertExactAttribute("true", "metatype:MetaData/OCD/AD[@id='notSoSimple']/@foo:booleanAttr2"); xt.assertCount(4, "metatype:MetaData/OCD/AD[@id='stringCollection']/@*"); xt.assertCount(9, "metatype:MetaData/OCD/AD[@id='enabled']/@*"); xt.assertExactAttribute("ad2", "metatype:MetaData/OCD/AD[@id='enabled']/@foo:stringAttr2"); xt.assertExactAttribute("A", "metatype:MetaData/OCD/AD[@id='enabled']/@foo:fooAttr2"); xt.assertExactAttribute(Object.class.getName(), "metatype:MetaData/OCD/AD[@id='enabled']/@foo:classAttr2"); xt.assertExactAttribute("true", "metatype:MetaData/OCD/AD[@id='enabled']/@foo:booleanAttr2"); } @XMLAttribute(namespace = "org.foo.extensions.v1", prefix = "foo", embedIn = "*", mapping = { "value=simple" }) @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE, ElementType.METHOD }) @interface Simple { String value() default "default"; } @Simple @ObjectClassDefinition @interface SimpleConfig { @Simple("value") @AttributeDefinition String[] property(); } public void testSimpleExtensions() throws Exception { MetatypeVersion version = MetatypeVersion.VERSION_1_2; Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, SimpleConfig.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$SimpleConfig.xml"); assertEquals(0, b.getErrors().size()); assertEquals("warnings: " + b.getWarnings(), 0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = new XmlTester(r.openInputStream(), "metatype", version.getNamespace(), "foo", "org.foo.extensions.v1"); xt.assertNamespace(version.getNamespace()); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$SimpleConfig", "metatype:MetaData/OCD/@id"); xt.assertCount(4, "metatype:MetaData/OCD/@*"); xt.assertExactAttribute("default", "metatype:MetaData/OCD/@foo:simple"); xt.assertCount(5, "metatype:MetaData/OCD/AD[@id='property']/@*"); xt.assertExactAttribute("value", "metatype:MetaData/OCD/AD[@id='property']/@foo:simple"); } @XMLAttribute(namespace = "org.foo.extensions.v1", prefix = "foo", embedIn = "*", mapping = { "a=first", "b=second" }) @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE, ElementType.METHOD }) @interface Mapping { String a() default "A"; String b() default "B"; } @Mapping @ObjectClassDefinition @interface MappingConfig { @Mapping(a = "one", b = "two") @AttributeDefinition String[] property(); } public void testMappingExtensions() throws Exception { MetatypeVersion version = MetatypeVersion.VERSION_1_2; Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, MappingConfig.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$MappingConfig.xml"); assertEquals(0, b.getErrors().size()); assertEquals("warnings: " + b.getWarnings(), 0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = new XmlTester(r.openInputStream(), "metatype", version.getNamespace(), "foo", "org.foo.extensions.v1"); xt.assertNamespace(version.getNamespace()); xt.assertExactAttribute("test.metatype.SpecMetatypeTest$MappingConfig", "metatype:MetaData/OCD/@id"); xt.assertCount(5, "metatype:MetaData/OCD/@*"); xt.assertExactAttribute("A", "metatype:MetaData/OCD/@foo:first"); xt.assertExactAttribute("B", "metatype:MetaData/OCD/@foo:second"); xt.assertCount(6, "metatype:MetaData/OCD/AD[@id='property']/@*"); xt.assertExactAttribute("one", "metatype:MetaData/OCD/AD[@id='property']/@foo:first"); xt.assertExactAttribute("two", "metatype:MetaData/OCD/AD[@id='property']/@foo:second"); } @ObjectClassDefinition @interface Escapes { @AttributeDefinition(defaultValue = { " , \\", "a,b", "c,d", "'apostrophe'", "\"quote\"&" }) String[] escapes(); } public void testEscapes() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, Escapes.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$Escapes.xml"); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); System.err.println(b.getJar().getResources().keySet()); assertNotNull(r); IO.copy(r.openInputStream(), System.err); XmlTester xt = xmlTester12(r); assertAD(xt, "escapes", "Escapes", null, null, "\\ \\,\\ \\\\,a\\,b,c\\,d,'apostrophe',\"quote\"&", 2147483647, "String", null, null, null); } @Mapping @Meta.OCD static interface C { @Meta.AD(required = false) Integer port(); } // cf issue 1130 public void testBndAnnoCompatible() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Export-Package", "test.metatype"); b.setProperty(Constants.METATYPE_ANNOTATIONS, C.class.getName()); b.build(); Resource r = b.getJar().getResource("OSGI-INF/metatype/test.metatype.SpecMetatypeTest$C.xml"); assertEquals(0, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); assertNull(r); } }