Author: alien11689 Date: Sat Jun 4 19:46:45 2016 New Revision: 1746848 URL: http://svn.apache.org/viewvc?rev=1746848&view=rev Log: [ARIES-1562] Allow for setter injection
Added: aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/test/BeanWithSetters.java Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Bean.java aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/BeanRef.java aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Context.java aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Introspector.java aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/OsgiServiceRef.java aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Property.java aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/GeneratorTest.java Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Bean.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Bean.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Bean.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Bean.java Sat Jun 4 19:46:45 2016 @@ -94,6 +94,12 @@ public class Bean extends BeanRef { properties.add(prop); } } + for (Method method : new Introspector(clazz).methodsWith(Value.class, Autowired.class, Inject.class)) { + Property prop = Property.create(matcher, method); + if (prop != null) { + properties.add(prop); + } + } } protected void resolveArguments(Matcher matcher) { Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/BeanRef.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/BeanRef.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/BeanRef.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/BeanRef.java Sat Jun 4 19:46:45 2016 @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * <p> + * <p/> * http://www.apache.org/licenses/LICENSE-2.0 - * <p> + * <p/> * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -24,6 +24,7 @@ import javax.inject.Named; import javax.inject.Qualifier; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -50,6 +51,16 @@ public class BeanRef implements Comparab setQualifiersFromAnnotations(annotations); } + public BeanRef(Method method) { + this(method.getParameterTypes()[0]); + Annotation[] annotations = method.getAnnotations(); + setQualifiersFromAnnotations(annotations); + Named named = method.getAnnotation(Named.class); + if (named != null) { + id = named.value(); + } + } + protected void setQualifiersFromAnnotations(Annotation[] annotations) { for (Annotation ann : annotations) { if (isQualifier(ann) != null) { @@ -81,6 +92,9 @@ public class BeanRef implements Comparab public boolean matches(BeanRef template) { boolean assignable = template.clazz.isAssignableFrom(this.clazz); + if (template.id != null) { + return template.id.equals(id); + } return assignable && qualifiers.values().containsAll(template.qualifiers.values()); } Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Context.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Context.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Context.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Context.java Sat Jun 4 19:46:45 2016 @@ -105,6 +105,9 @@ public class Context implements Matcher for (Field field : new Introspector(clazz).fieldsWith(OsgiService.class)) { reg.add(new OsgiServiceRef(field)); } + for (Method method : new Introspector(clazz).methodsWith(OsgiService.class)) { + reg.add(new OsgiServiceRef(method)); + } } public void resolve() { Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Introspector.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Introspector.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Introspector.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Introspector.java Sat Jun 4 19:46:45 2016 @@ -18,6 +18,13 @@ */ package org.apache.aries.blueprint.plugin.model; +import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; + import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -26,13 +33,6 @@ import java.util.Collection; import java.util.List; import java.util.Set; -import com.google.common.base.Preconditions; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - /** * Class to find uniquely-named fields declared in a class hierarchy with specified annotations. */ @@ -84,7 +84,6 @@ public final class Introspector { /** * Check that each field name is defined no more than once - * @param originalClazz * @param acceptedFieldName * @param acceptedFieldsWithSameName */ @@ -122,12 +121,15 @@ public final class Introspector { return Iterables.getOnlyElement(methods, null); } - public <T extends Annotation> List<Method> methodsWith(Class<T> annotationClass) { + @SafeVarargs + public final List<Method> methodsWith(Class<? extends Annotation>... annotationClasses) { List<Method> methods = new ArrayList<>(); for (Method method : originalClazz.getMethods()) { - T annotation = method.getAnnotation(annotationClass); - if (annotation != null) { - methods.add(method); + for(Class<? extends Annotation> annotationClass : annotationClasses) { + if (method.getAnnotation(annotationClass) != null) { + methods.add(method); + break; + } } } return methods; Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/OsgiServiceRef.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/OsgiServiceRef.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/OsgiServiceRef.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/OsgiServiceRef.java Sat Jun 4 19:46:45 2016 @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,10 +18,11 @@ */ package org.apache.aries.blueprint.plugin.model; -import java.lang.reflect.Field; - import org.ops4j.pax.cdi.api.OsgiService; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + /** * Synthetic bean that refers to an OSGi service */ @@ -30,7 +31,6 @@ public class OsgiServiceRef extends Bean final public String filter; final public String compName; - public OsgiServiceRef(Field field) { super(field); OsgiService osgiService = field.getAnnotation(OsgiService.class); @@ -46,6 +46,32 @@ public class OsgiServiceRef extends Bean if (filter != null) { id = id + "-" + getId(filter); } + if (compName != null) { + id = id + "-" + compName; + } + } + + public OsgiServiceRef(Method method) { + super(method); + OsgiService osgiService = method.getAnnotation(OsgiService.class); + String filterValue = osgiService.filter(); + if (filterValue.contains("(")) { + filter = filterValue; + compName = null; + } else { + compName = filterValue; + filter = null; + } + if (id != null) { + return; + } + id = getBeanName(clazz); + if (filter != null) { + id = id + "-" + getId(filter); + } + if (compName != null) { + id = id + "-" + compName; + } } public OsgiServiceRef(Class<?> clazz, OsgiService osgiService, String name) { Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Property.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Property.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Property.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/main/java/org/apache/aries/blueprint/plugin/model/Property.java Sat Jun 4 19:46:45 2016 @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,15 +18,16 @@ */ package org.apache.aries.blueprint.plugin.model; -import java.lang.reflect.Field; - -import javax.inject.Inject; -import javax.inject.Named; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import javax.inject.Inject; +import javax.inject.Named; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + public class Property implements Comparable<Property> { public String name; public String ref; @@ -44,7 +45,7 @@ public class Property implements Compara BeanRef matching = matcher.getMatching(new BeanRef(field)); String ref = (matching == null) ? getRefName(field) : matching.id; return new Property(field.getName(), ref, null); - } else if (value != null){ + } else if (value != null) { return new Property(field.getName(), null, cleanValue(value.value())); } else { // Field is not a property @@ -52,6 +53,35 @@ public class Property implements Compara } } + public static Property create(Matcher matcher, Method method) { + String propertyName = resolveProperty(method); + if (propertyName == null) { + return null; + } + + Value value = method.getAnnotation(Value.class); + if (value != null) { + return new Property(propertyName, null, cleanValue(value.value())); + } + + if (needsInject(method)) { + BeanRef beanRef = new BeanRef(method); + BeanRef matching = matcher.getMatching(beanRef); + String ref = (matching == null) ? beanRef.id : matching.id; + return new Property(propertyName, ref, null); + } + + return null; + } + + private static String resolveProperty(Method method) { + if (method.getParameterTypes().length != 1) { + return null; + } + String propertyName = method.getName().substring(3); + return makeFirstLetterLower(propertyName); + } + /** * Assume it is defined in another manually created blueprint context with default name * @param field @@ -62,20 +92,20 @@ public class Property implements Compara if (named != null) { return named.value(); } - Qualifier qualifier = field.getAnnotation(Qualifier.class); + Qualifier qualifier = field.getAnnotation(Qualifier.class); if (qualifier != null) { return qualifier.value(); } return Bean.getBeanName(field.getType()); } - private static boolean needsInject(Field field) { - return field.getAnnotation(Autowired.class) != null || field.getAnnotation(Inject.class) != null; + private static boolean needsInject(AnnotatedElement annotatedElement) { + return annotatedElement.getAnnotation(Autowired.class) != null || annotatedElement.getAnnotation(Inject.class) != null; } /** * Remove default value definition - * + * * @param value * @return */ @@ -88,4 +118,7 @@ public class Property implements Compara return name.compareTo(other.name); } + private static String makeFirstLetterLower(String name) { + return name.substring(0, 1).toLowerCase() + name.substring(1, name.length()); + } } Modified: aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/GeneratorTest.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/GeneratorTest.java?rev=1746848&r1=1746847&r2=1746848&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/GeneratorTest.java (original) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/GeneratorTest.java Sat Jun 4 19:46:45 2016 @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * <p> + * <p/> * http://www.apache.org/licenses/LICENSE-2.0 - * <p> + * <p/> * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -95,12 +95,12 @@ public class GeneratorTest { defs.add(new TransactionalDef(xpath.evaluate("@method", tx), xpath.evaluate("@value", tx))); } Set<TransactionalDef> expectedDefs = Sets.newHashSet(new TransactionalDef("*", "RequiresNew"), - new TransactionalDef("txNotSupported", "NotSupported"), - new TransactionalDef("txMandatory", "Mandatory"), - new TransactionalDef("txNever", "Never"), - new TransactionalDef("txRequired", "Required"), - new TransactionalDef("txOverridenWithRequiresNew", "RequiresNew"), - new TransactionalDef("txSupports", "Supports")); + new TransactionalDef("txNotSupported", "NotSupported"), + new TransactionalDef("txMandatory", "Mandatory"), + new TransactionalDef("txNever", "Never"), + new TransactionalDef("txRequired", "Required"), + new TransactionalDef("txOverridenWithRequiresNew", "RequiresNew"), + new TransactionalDef("txSupports", "Supports")); assertEquals(expectedDefs, defs); } @@ -156,7 +156,7 @@ public class GeneratorTest { interfaceNames.add(interfaceValue.getTextContent()); } assertEquals(Sets.newHashSet(ServiceA.class.getName(), ServiceB.class.getName()), - interfaceNames); + interfaceNames); } @Test @@ -262,8 +262,40 @@ public class GeneratorTest { assertEquals("v2", xpath.evaluate("service-properties/entry[@key='n2']/@value", service)); } + @Test + public void testSetterInjection() throws Exception { + Node bean1 = getBeanById("beanWithSetters"); + + assertEquals("0", xpath.evaluate("count(property[@name='useless'])", bean1)); + assertEquals("0", xpath.evaluate("count(property[@name='iOnlyHaveSetPrefix'])", bean1)); + assertEquals("0", xpath.evaluate("count(property[@name='ihaveMoreThenOneParameter'])", bean1)); + assertEquals("0", xpath.evaluate("count(property[@name='iOnlyHaveSetPrefixValue'])", bean1)); + assertEquals("0", xpath.evaluate("count(property[@name='ihaveMoreThenOneParameterValue'])", bean1)); + + assertEquals("test", xpath.evaluate("property[@name='myValue']/@value", bean1)); + assertEquals("my1", xpath.evaluate("property[@name='serviceA1']/@ref", bean1)); + assertEquals("my1", xpath.evaluate("property[@name='serviceA2']/@ref", bean1)); + assertEquals("serviceABImpl", xpath.evaluate("property[@name='serviceB']/@ref", bean1)); + assertEquals("serviceB2Id", xpath.evaluate("property[@name='serviceB2']/@ref", bean1)); + assertEquals("serviceB-typeB1Ref", xpath.evaluate("property[@name='serviceBRef']/@ref", bean1)); + assertEquals("serviceB2IdRef", xpath.evaluate("property[@name='serviceB2Ref']/@ref", bean1)); + assertEquals("serviceB-B3Ref", xpath.evaluate("property[@name='serviceB3Ref']/@ref", bean1)); + + Node reference1 = getReferenceById("serviceB-typeB1Ref"); + assertEquals(ServiceB.class.getName(), xpath.evaluate("@interface", reference1)); + assertEquals("(type=B1Ref)", xpath.evaluate("@filter", reference1)); + + Node reference2 = getReferenceById("serviceB2IdRef"); + assertEquals(ServiceB.class.getName(), xpath.evaluate("@interface", reference2)); + assertEquals("(type=B2Ref)", xpath.evaluate("@filter", reference2)); + + Node reference3 = getReferenceById("serviceB-B3Ref"); + assertEquals(ServiceB.class.getName(), xpath.evaluate("@interface", reference3)); + assertEquals("B3Ref", xpath.evaluate("@component-name", reference3)); + } + private static Document readToDocument(ByteArrayOutputStream os) throws ParserConfigurationException, - SAXException, IOException { + SAXException, IOException { InputStream is = new ByteArrayInputStream(os.toByteArray()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Added: aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/test/BeanWithSetters.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/test/BeanWithSetters.java?rev=1746848&view=auto ============================================================================== --- aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/test/BeanWithSetters.java (added) +++ aries/trunk/blueprint/blueprint-maven-plugin/src/test/java/org/apache/aries/blueprint/plugin/test/BeanWithSetters.java Sat Jun 4 19:46:45 2016 @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.aries.blueprint.plugin.test; + +import org.ops4j.pax.cdi.api.OsgiService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +@Singleton +public class BeanWithSetters { + + @Inject + @Named("my1") + public void setServiceA1(ServiceA serviceA1) { + } + + @Inject + @Qualifier("my2") + public void setServiceA2(ServiceA serviceA2) { + } + + @Autowired + public void setServiceB(ServiceB serviceB) { + } + + @Inject + @Named("serviceB2Id") + public void setServiceB2(ServiceB serviceB2) { + } + + public void setUseless(MyProduced myProduced) { + } + + @Inject + public void setIOnlyHaveSetPrefix() { + } + + @Inject + public void setIhaveMoreThenOneParameter(String a, String b) { + } + + @Value("test") + public void setIOnlyHaveSetPrefixValue() { + } + + @Value("test") + public void setIhaveMoreThenOneParameterValue(String a, String b) { + } + + @Value("test") + public void setMyValue(String v) { + } + + @Inject + @OsgiService(filter = "(type=B1Ref)") + public void setServiceBRef(ServiceB serviceBRef) { + } + + + @Inject + @Named("serviceB2IdRef") + @OsgiService(filter = "(type=B2Ref)") + public void setServiceB2Ref(ServiceB serviceB2Ref) { + } + + @Inject + @OsgiService(filter = "B3Ref") + public void setServiceB3Ref(ServiceB serviceB3Ref) { + } +}