You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by da...@apache.org on 2017/03/20 21:26:00 UTC
svn commit: r1787850 - in /felix/trunk/converter/converter/src:
main/java/org/apache/felix/converter/impl/
test/java/org/apache/felix/converter/impl/
Author: davidb
Date: Mon Mar 20 21:26:00 2017
New Revision: 1787850
URL: http://svn.apache.org/viewvc?rev=1787850&view=rev
Log:
Support conversions from SingleElementAnnotations.
Modified:
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/DynamicMapLikeFacade.java
felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/Util.java
felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java
Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java?rev=1787850&r1=1787849&r2=1787850&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java Mon Mar 20 21:26:00 2017
@@ -450,7 +450,7 @@ public class ConvertingImpl implements C
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- String propName = Util.getInterfacePropertyName(method);
+ String propName = Util.getInterfacePropertyName(method, Util.getSingleElementAnnotationKey(targetCls, proxy), proxy);
if (propName == null)
return null;
@@ -714,7 +714,7 @@ public class ConvertingImpl implements C
Map result = new HashMap();
for (Class i : obj.getClass().getInterfaces()) {
for (Method md : i.getMethods()) {
- handleInterfaceMethod(obj, md, new HashSet<>(), result);
+ handleInterfaceMethod(obj, i, md, new HashSet<>(), result);
}
if (result.size() > 0)
return result;
@@ -801,12 +801,12 @@ public class ConvertingImpl implements C
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private static void handleInterfaceMethod(Object obj, Method md, Set<String> invokedMethods, Map res) {
+ private static void handleInterfaceMethod(Object obj, Class<?> intf, Method md, Set<String> invokedMethods, Map res) {
String mn = md.getName();
if (invokedMethods.contains(mn))
return; // method with this name already invoked
- String propName = Util.getInterfacePropertyName(md);
+ String propName = Util.getInterfacePropertyName(md, Util.getSingleElementAnnotationKey(intf, obj), obj);
if (propName == null)
return;
Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/DynamicMapLikeFacade.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/DynamicMapLikeFacade.java?rev=1787850&r1=1787849&r2=1787850&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/DynamicMapLikeFacade.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/DynamicMapLikeFacade.java Mon Mar 20 21:26:00 2017
@@ -267,7 +267,7 @@ class DynamicInterfaceFacade extends Dyn
private Map<String, Set<Method>> getKeys() {
if (keys == null)
- keys = Util.getInterfaceKeys(convertingImpl.sourceClass);
+ keys = Util.getInterfaceKeys(convertingImpl.sourceClass, backingObject);
return keys;
}
Modified: felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/Util.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/Util.java?rev=1787850&r1=1787849&r2=1787850&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/Util.java (original)
+++ felix/trunk/converter/converter/src/main/java/org/apache/felix/converter/impl/Util.java Mon Mar 20 21:26:00 2017
@@ -140,11 +140,12 @@ class Util {
return unMangleName(getPrefix(f.getDeclaringClass()), f.getName());
}
- static Map<String, Set<Method>> getInterfaceKeys(Class<?> intf) {
+ static Map<String, Set<Method>> getInterfaceKeys(Class<?> intf, Object object) {
Map<String, Set<Method>> keys = new LinkedHashMap<>();
+ String seank = getSingleElementAnnotationKey(intf, object);
for (Method md : intf.getMethods()) {
- String name = getInterfacePropertyName(md);
+ String name = getInterfacePropertyName(md, seank, object);
if (name != null) {
Set<Method> set = keys.get(name);
if (set == null) {
@@ -171,17 +172,87 @@ class Util {
return keys;
}
- static String getInterfacePropertyName(Method md) {
+ static String getSingleElementAnnotationKey(Class<?> intf, Object obj) {
+ Class<?> ann = getAnnotationType(intf, obj);
+ if (ann == null)
+ return null;
+
+ boolean valueFound = false;
+ for (Method md : ann.getDeclaredMethods()) {
+ if ("value".equals(md.getName())) {
+ valueFound = true;
+ continue;
+ }
+
+ if (md.getDefaultValue() == null) {
+ // All elements bar value must have a default
+ return null;
+ }
+ }
+
+ if (!valueFound) {
+ // Single Element Annotation must have a value element.
+ return null;
+ }
+
+ return toSingleElementAnnotationKey(ann.getSimpleName());
+ }
+
+ private static Class<?> getAnnotationType(Class<?> intf, Object obj) {
+ try {
+ Method md = intf.getMethod("annotationType");
+ Object res = md.invoke(obj);
+ if (res instanceof Class)
+ return (Class<?>) res;
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ private static String toSingleElementAnnotationKey(String simpleName) {
+ StringBuilder sb = new StringBuilder();
+
+ boolean capitalSeen = true;
+ for (char c : simpleName.toCharArray()) {
+ if (!capitalSeen) {
+ if (Character.isUpperCase(c)) {
+ capitalSeen = true;
+ sb.append('.');
+ }
+ } else {
+ if (Character.isLowerCase(c)) {
+ capitalSeen = false;
+ }
+ }
+ sb.append(Character.toLowerCase(c));
+ }
+
+ return sb.toString();
+ }
+
+ static String getInterfacePropertyName(Method md, String singleElementAnnotationKey, Object object) {
if (md.getReturnType().equals(Void.class))
return null; // not an accessor
if (md.getParameterTypes().length > 1)
return null; // not an accessor
+ if ("value".equals(md.getName()) && md.getParameterTypes().length == 0 && singleElementAnnotationKey != null)
+ return singleElementAnnotationKey;
+
if (Object.class.equals(md.getDeclaringClass()) ||
Annotation.class.equals(md.getDeclaringClass()))
return null; // do not use any methods on the Object or Annotation class as a accessor
+ if ("annotationType".equals(md.getName())) {
+ try {
+ Object cls = md.invoke(object);
+ if (cls instanceof Class && ((Class<?>) cls).isAnnotation())
+ return null;
+ } catch (Exception e) {
+ }
+ }
+
if (md.getDeclaringClass().getSimpleName().startsWith("$Proxy")) {
// TODO is there a better way to do this?
if (isInheritedMethodInProxy(md, Object.class) ||
Modified: felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java?rev=1787850&r1=1787849&r2=1787850&view=diff
==============================================================================
--- felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java (original)
+++ felix/trunk/converter/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java Mon Mar 20 21:26:00 2017
@@ -16,6 +16,7 @@
*/
package org.apache.felix.converter.impl;
+import java.lang.annotation.Annotation;
import java.math.BigInteger;
import java.net.URL;
import java.text.SimpleDateFormat;
@@ -258,6 +259,37 @@ public class ConverterMapTest {
}
}
+ @Test
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void testSingleElementAnnotation() {
+ class MySingleElementAnnotation implements SingleElementAnnotation {
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return SingleElementAnnotation.class;
+ }
+
+ @Override
+ public String[] value() {
+ return new String[] {"hi", "there"};
+ }
+
+ @Override
+ public long somethingElse() {
+ return 42;
+ }
+ };
+ MySingleElementAnnotation sea = new MySingleElementAnnotation();
+ Map m = converter.convert(sea).to(Map.class);
+ Map expected = new HashMap();
+ expected.put("single.element.annotation", new String[] {"hi", "there"});
+ expected.put("somethingElse", 42);
+ assertEquals(2, m.size());
+ assertArrayEquals(new String[] {"hi", "there"}, (String []) m.get("single.element.annotation"));
+ assertEquals(42L, m.get("somethingElse"));
+
+ // TODO support conversion in the other direction too.
+ }
+
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testCopyMap() {
@@ -281,4 +313,9 @@ public class ConverterMapTest {
int bar() default 42;
boolean za_za();
}
+
+ @interface SingleElementAnnotation {
+ String[] value();
+ long somethingElse() default -87;
+ }
}