1 package org.onap.sdc.dcae.catalog.commons;
5 import java.util.Collections;
7 import java.util.stream.Collectors;
9 import java.lang.annotation.ElementType;
10 import java.lang.annotation.Retention;
11 import java.lang.annotation.RetentionPolicy;
12 import java.lang.annotation.Target;
14 import java.lang.reflect.Type;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Array;
17 import java.lang.reflect.Constructor;
18 import java.lang.reflect.ParameterizedType;
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.InvocationTargetException;
22 import java.lang.invoke.MethodHandles;
24 import com.google.common.reflect.Invokable;
25 import com.google.common.reflect.AbstractInvocationHandler;
27 import org.apache.commons.beanutils.ConvertUtils;
33 extends AbstractInvocationHandler {
35 @Retention(RetentionPolicy.RUNTIME)
36 @Target(ElementType.METHOD)
38 public static @interface DataMap {
40 public String map() default "";
42 public boolean proxy() default false;
44 public Class elementType() default Void.class;
48 public static Constructor<MethodHandles.Lookup> lookupHandleConstructor;
52 lookupHandleConstructor =
53 MethodHandles.Lookup.class.getDeclaredConstructor(Class.class,
56 if (!lookupHandleConstructor.isAccessible()) {
57 lookupHandleConstructor.setAccessible(true);
61 throw new RuntimeException(x);
67 private ProxyBuilder builder;
69 protected Proxy(Map theData, ProxyBuilder theBuilder) {
71 this.builder = theBuilder;
78 public ProxyBuilder getBuilder() {
82 protected Object handleInvocation(
83 Object theProxy,Method theMethod,Object[] theArgs)
85 if (theMethod.isDefault()) {
86 final Class<?> declaringClass = theMethod.getDeclaringClass();
88 return MethodHandles.lookup()
90 .unreflectSpecial(theMethod, declaringClass)
92 .invokeWithArguments(theArgs);
94 return lookupHandleConstructor
95 .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
96 .unreflectSpecial(theMethod, declaringClass)
98 .invokeWithArguments(theArgs);
101 String key = theMethod.getName();
103 Proxy.DataMap dataMap = (Proxy.DataMap)theMethod.getAnnotation(Proxy.DataMap.class);
104 if (dataMap != null) {
105 String dataKey = dataMap.map();
106 if (dataKey != null && !"".equals(dataKey))
110 //this is ugly, can this be done through an extension mechanism such as plugging in functions?
111 if ( builder.hasExtension(key) )
112 return this.builder.extension(key).apply(this, theArgs);
114 Object val = this.data.getOrDefault(key, this.builder.context(key));
116 System.out.println("!! " + key + " : " + val);
118 //as we create proxies here we should store them back in the 'data' so that we do not do it again
119 //can we always 'recognize' them?
120 if (val instanceof String &&
121 String.class != theMethod.getReturnType()) {
122 return ConvertUtils.convert((String)val, theMethod.getReturnType());
124 else if (val instanceof Map) {
125 if (dataMap != null && dataMap.proxy()) {
126 return builder.build((Map)val, theMethod.getReturnType());
129 else if (val instanceof List) {
130 if (dataMap != null && dataMap.proxy()) {
133 .map(e -> this.builder.build((Map)e, dataMap.elementType()))
134 .collect(Collectors.toList());
138 else if (val.getClass().isArray()) {
139 if (dataMap != null && dataMap.proxy()) {