Skip to content

Commit

Permalink
Emit annotation defaults into generated extension xml attributes when…
Browse files Browse the repository at this point in the history
… not overridden

Signed-off-by David Jencks <david_jencks@yahoo.com>
  • Loading branch information
djencks committed May 29, 2015
1 parent 188aaea commit 3d8c305
Show file tree
Hide file tree
Showing 15 changed files with 400 additions and 153 deletions.
106 changes: 70 additions & 36 deletions biz.aQute.bndlib.tests/src/test/component/DSAnnotationTest.java
@@ -1,24 +1,51 @@
package test.component;

import java.io.*;
import java.lang.annotation.*;
import java.util.*;
import java.util.jar.*;

import javax.xml.xpath.*;

import org.osgi.framework.*;
import org.osgi.service.component.*;
import org.osgi.service.component.annotations.*;
import org.osgi.service.log.*;
import org.osgi.service.metatype.annotations.*;

import aQute.bnd.annotation.xml.*;
import aQute.bnd.component.*;
import aQute.bnd.header.*;
import aQute.bnd.osgi.*;
import java.io.File;
import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

import javax.xml.xpath.XPathExpressionException;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.ComponentServiceObjects;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.FieldOption;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.component.annotations.ServiceScope;
import org.osgi.service.log.LogService;
import org.osgi.service.metatype.annotations.Designate;

import aQute.bnd.annotation.xml.XMLAttribute;
import aQute.bnd.component.AnnotationReader;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Builder;
import aQute.bnd.osgi.Constants;
import aQute.bnd.test.*;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Processor;
import aQute.bnd.osgi.Resource;
import aQute.bnd.test.BndTestCase;
import aQute.bnd.test.XmlTester;

/**
* #118
Expand Down Expand Up @@ -2501,7 +2528,7 @@ static void checkConfigurationPolicy(Jar jar, Class< ? > clazz, String option) t

@TestExtensions(stringAttr = "bar", fooAttr = Foo.A)
@Component
public static class ExtraAttrbutes implements Serializable, Runnable {
public static class ExtraAttributes implements Serializable, Runnable {
private static final long serialVersionUID = 1L;

@Activate
Expand Down Expand Up @@ -2531,16 +2558,16 @@ void modified(@SuppressWarnings("unused") ComponentContext cc) {}
public void run() {}
}

public static void testExtraAttrbutes() throws Exception {
public static void testExtraAttributes() throws Exception {
Builder b = new Builder();
b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$ExtraAttrbutes*");
b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$ExtraAttributes*");
b.setProperty("Private-Package", "test.component");
b.addClasspath(new File("bin"));

Jar jar = b.build();
assertOk(b);

String name = ExtraAttrbutes.class.getName();
String name = ExtraAttributes.class.getName();
Resource r = jar.getResource("OSGI-INF/" + name + ".xml");
System.err.println(Processor.join(jar.getResources().keySet(), "\n"));
assertNotNull(r);
Expand All @@ -2553,14 +2580,16 @@ public static void testExtraAttrbutes() throws Exception {
// Default must be the implementation class
xt.assertAttribute(name, "scr:component/@name");

xt.assertCount(6, "scr:component/@*");
xt.assertCount(7, "scr:component/@*");
xt.assertAttribute("bar", "scr:component/@foo:stringAttr");
xt.assertAttribute("A", "scr:component/@foo:fooAttr");
xt.assertAttribute("true", "scr:component/@foo:booleanAttr");

xt.assertCount(3, "scr:component/reference");
xt.assertCount(5, "scr:component/reference[1]/@*");
xt.assertCount(6, "scr:component/reference[1]/@*");
xt.assertAttribute("bax", "scr:component/reference[1]/@foo:stringAttr2");
xt.assertAttribute("A", "scr:component/reference[1]/@foo:fooAttr2");
xt.assertAttribute("true", "scr:component/reference[1]/@foo:booleanAttr2");

xt.assertCount(3, "scr:component/reference[2]/@*");
xt.assertCount(6, "scr:component/reference[3]/@*");
Expand All @@ -2575,7 +2604,7 @@ public static void testExtraAttrbutes() throws Exception {
ElementType.TYPE
})
@interface TestExtensions3 {
boolean booleanAttr3() default true;
boolean booleanAttr3() default false;

String stringAttr3();

Expand All @@ -2585,7 +2614,7 @@ public static void testExtraAttrbutes() throws Exception {
@TestExtensions(stringAttr = "bar", fooAttr = Foo.A)
@TestExtensions3(stringAttr3 = "bar3", fooAttr3 = Foo.B)
@Component
public static class PrefixCollisionExtraAttrbutes implements Serializable, Runnable {
public static class PrefixCollisionExtraAttributes implements Serializable, Runnable {
private static final long serialVersionUID = 1L;

@Activate
Expand Down Expand Up @@ -2615,16 +2644,16 @@ void modified(@SuppressWarnings("unused") ComponentContext cc) {}
public void run() {}
}

public static void testPrefixCollisionExtraAttrbutes() throws Exception {
public static void testPrefixCollisionExtraAttributes() throws Exception {
Builder b = new Builder();
b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$PrefixCollisionExtraAttrbutes*");
b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$PrefixCollisionExtraAttributes*");
b.setProperty("Private-Package", "test.component");
b.addClasspath(new File("bin"));

Jar jar = b.build();
assertOk(b);

String name = PrefixCollisionExtraAttrbutes.class.getName();
String name = PrefixCollisionExtraAttributes.class.getName();
Resource r = jar.getResource("OSGI-INF/" + name + ".xml");
System.err.println(Processor.join(jar.getResources().keySet(), "\n"));
assertNotNull(r);
Expand All @@ -2637,16 +2666,19 @@ public static void testPrefixCollisionExtraAttrbutes() throws Exception {
// Default must be the implementation class
xt.assertAttribute(name, "scr:component/@name");

xt.assertCount(8, "scr:component/@*");
xt.assertCount(10, "scr:component/@*");
xt.assertAttribute("bar", "scr:component/@foo:stringAttr");
xt.assertAttribute("A", "scr:component/@foo:fooAttr");
xt.assertAttribute("true", "scr:component/@foo:booleanAttr");
xt.assertAttribute("bar3", "scr:component/@foo1:stringAttr3");
xt.assertAttribute("B", "scr:component/@foo1:fooAttr3");
xt.assertAttribute("false", "scr:component/@foo1:booleanAttr3");

xt.assertCount(3, "scr:component/reference");
xt.assertCount(5, "scr:component/reference[1]/@*");
xt.assertCount(6, "scr:component/reference[1]/@*");
xt.assertAttribute("bax", "scr:component/reference[1]/@foo:stringAttr2");
xt.assertAttribute("A", "scr:component/reference[1]/@foo:fooAttr2");
xt.assertAttribute("true", "scr:component/reference[1]/@foo:booleanAttr2");

xt.assertCount(3, "scr:component/reference[2]/@*");
xt.assertCount(6, "scr:component/reference[3]/@*");
Expand Down Expand Up @@ -2684,7 +2716,7 @@ public static void testPrefixCollisionExtraAttrbutes() throws Exception {
@TestExtensions4(stringAttr4 = "bar", fooAttr4 = Foo.A)
@TestExtensions5(stringAttr5 = "bar3", fooAttr5 = Foo.B)
@Component
public static class DefaultPrefixCollisionExtraAttrbutes implements Serializable, Runnable {
public static class DefaultPrefixCollisionExtraAttributes implements Serializable, Runnable {
private static final long serialVersionUID = 1L;

@Activate
Expand All @@ -2702,16 +2734,16 @@ void modified(@SuppressWarnings("unused") ComponentContext cc) {}
public void run() {}
}

public static void testPrefixCollisionExtraAttrbutesDefaultPrefix() throws Exception {
public static void testPrefixCollisionExtraAttributesDefaultPrefix() throws Exception {
Builder b = new Builder();
b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DefaultPrefixCollisionExtraAttrbutes*");
b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DefaultPrefixCollisionExtraAttributes*");
b.setProperty("Private-Package", "test.component");
b.addClasspath(new File("bin"));

Jar jar = b.build();
assertOk(b);

String name = DefaultPrefixCollisionExtraAttrbutes.class.getName();
String name = DefaultPrefixCollisionExtraAttributes.class.getName();
Resource r = jar.getResource("OSGI-INF/" + name + ".xml");
System.err.println(Processor.join(jar.getResources().keySet(), "\n"));
assertNotNull(r);
Expand All @@ -2724,11 +2756,13 @@ public static void testPrefixCollisionExtraAttrbutesDefaultPrefix() throws Excep
// Default must be the implementation class
xt.assertAttribute(name, "scr:component/@name");

xt.assertCount(8, "scr:component/@*");
xt.assertCount(10, "scr:component/@*");
xt.assertAttribute("bar", "scr:component/@ns:stringAttr4");
xt.assertAttribute("A", "scr:component/@ns:fooAttr4");
xt.assertAttribute("true", "scr:component/@ns:booleanAttr4");
xt.assertAttribute("bar3", "scr:component/@ns1:stringAttr5");
xt.assertAttribute("B", "scr:component/@ns1:fooAttr5");
xt.assertAttribute("true", "scr:component/@ns1:booleanAttr5");

}

Expand Down
10 changes: 7 additions & 3 deletions biz.aQute.bndlib.tests/src/test/metatype/SpecMetatypeTest.java
Expand Up @@ -1328,24 +1328,28 @@ public static void testExtensions() throws Exception {
xt.assertExactAttribute("true", "metatype:MetaData/OCD/AD[@id='enabled']/@default");
xt.assertExactAttribute(Integer.MAX_VALUE + "", "metatype:MetaData/OCD/AD[@id='notSoSimple']/@cardinality");

xt.assertCount(7, "metatype:MetaData/OCD/@*");
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(7, "metatype:MetaData/OCD/AD[@id='notSoSimple']/@*");
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(7, "metatype:MetaData/OCD/AD[@id='enabled']/@*");
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");

}

Expand Down
83 changes: 49 additions & 34 deletions biz.aQute.bndlib/src/aQute/bnd/component/AnnotationReader.java
@@ -1,35 +1,46 @@
package aQute.bnd.component;

import java.lang.reflect.*;
import java.util.*;
import java.util.Map.*;
import java.util.regex.*;

import org.osgi.service.component.annotations.*;
import org.osgi.service.metatype.annotations.*;

import aQute.bnd.annotation.xml.*;
import aQute.bnd.component.DSAnnotations.*;
import aQute.bnd.component.error.*;
import aQute.bnd.component.error.DeclarativeServicesAnnotationError.*;
import aQute.bnd.osgi.*;
import aQute.bnd.osgi.Clazz.*;
import aQute.bnd.osgi.Descriptors.*;
import aQute.bnd.version.*;
import aQute.bnd.xmlattribute.*;
import aQute.lib.collections.*;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferenceScope;
import org.osgi.service.component.annotations.ServiceScope;
import org.osgi.service.metatype.annotations.Designate;

import aQute.bnd.annotation.xml.XMLAttribute;
import aQute.bnd.component.DSAnnotations.Options;
import aQute.bnd.component.error.DeclarativeServicesAnnotationError;
import aQute.bnd.component.error.DeclarativeServicesAnnotationError.ErrorType;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Annotation;
import aQute.bnd.osgi.ClassDataCollector;
import aQute.bnd.osgi.Clazz;
import aQute.bnd.osgi.Clazz.FieldDef;
import aQute.bnd.osgi.Clazz.MethodDef;
import aQute.bnd.osgi.Descriptors;
import aQute.bnd.osgi.Descriptors.TypeRef;
import aQute.bnd.osgi.Verifier;
import aQute.bnd.version.Version;
import aQute.bnd.xmlattribute.XMLAttributeFinder;
import aQute.lib.collections.MultiMap;

/**
* fixup any unbind methods To declare no unbind method, the value "-" must be
* used. If not specified, the name of the unbind method is derived from the
* name of the annotated bind method. If the annotated method name begins with
* set, that is replaced with unset to derive the unbind method name. If the
* annotated method name begins with add, that is replaced with remove to derive
* the unbind method name. Otherwise, un is prefixed to the annotated method
* name to derive the unbind method name.
*
* @return
* @throws Exception
* Processes spec DS annotations into xml.
*/
public class AnnotationReader extends ClassDataCollector {
final static TypeRef[] EMPTY = new TypeRef[0];
Expand Down Expand Up @@ -71,7 +82,7 @@ public class AnnotationReader extends ClassDataCollector {
static Pattern DEACTIVATEDESCRIPTORDS13 = Pattern
.compile("\\(((L([^;]+);)|(I))*\\)(V|(Ljava/util/Map;))");

ComponentDef component = new ComponentDef();
ComponentDef component;

Clazz clazz;
TypeRef interfaces[];
Expand All @@ -94,6 +105,7 @@ public class AnnotationReader extends ClassDataCollector {
this.clazz = clazz;
this.options = options;
this.finder = finder;
this.component = new ComponentDef(finder);
}

public static ComponentDef getDefinition(Clazz c, Analyzer analyzer, EnumSet<Options> options, XMLAttributeFinder finder) throws Exception {
Expand Down Expand Up @@ -205,7 +217,7 @@ else if (a instanceof Designate)
else if (annotation.getName().getFQN().startsWith("aQute.bnd.annotation.component"))
handleMixedUsageError(annotation);
else {
XMLAttribute xmlAttr = finder.getXMLAttribute(annotation, analyzer);
XMLAttribute xmlAttr = finder.getXMLAttribute(annotation);
if (xmlAttr != null) {
doXmlAttribute(annotation, xmlAttr);
}
Expand Down Expand Up @@ -249,7 +261,7 @@ private void doXmlAttribute(Annotation annotation, XMLAttribute xmlAttr) {
else {
ReferenceDef ref = referencesByMember.get(member);
if (ref == null) {
ref = new ReferenceDef();
ref = new ReferenceDef(finder);
referencesByMember.put(member, ref);
}
ref.addExtensionAttribute(xmlAttr, annotation);
Expand Down Expand Up @@ -475,17 +487,20 @@ else if (m.group(3) != null) // $$ to $
}

/**
* @param annotation
* @param reference
* @Reference proxy backed by raw.
* @param raw
* @Reference contents
* @throws Exception
*/
protected void doReference(Reference reference, Annotation raw) throws Exception {
ReferenceDef def;
if (member == null)
def = new ReferenceDef();
def = new ReferenceDef(finder);
else if (referencesByMember.containsKey(member))
def = referencesByMember.get(member);
else {
def = new ReferenceDef();
def = new ReferenceDef(finder);
referencesByMember.put(member, def);
}
def.className = className.getFQN();
Expand Down

0 comments on commit 3d8c305

Please sign in to comment.