From 0b5eb2f4394d5e5556ad1f76984e4cbe5f97f091 Mon Sep 17 00:00:00 2001 From: crusader Date: Fri, 30 Jun 2017 14:08:08 +0900 Subject: [PATCH] Spring bean reflection --- .../loafle/overflow/proxy/ServiceInvoker.java | 194 ++++++++++++++++++ .../overflow/proxy/ServiceInvokerTest.java | 44 ++++ 2 files changed, 238 insertions(+) create mode 100644 src/main/java/com/loafle/overflow/proxy/ServiceInvoker.java create mode 100644 src/test/java/com/loafle/overflow/proxy/ServiceInvokerTest.java diff --git a/src/main/java/com/loafle/overflow/proxy/ServiceInvoker.java b/src/main/java/com/loafle/overflow/proxy/ServiceInvoker.java new file mode 100644 index 0000000..12d6d26 --- /dev/null +++ b/src/main/java/com/loafle/overflow/proxy/ServiceInvoker.java @@ -0,0 +1,194 @@ +package com.loafle.overflow.proxy; + +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.ObjectMapper; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by crusader on 17. 6. 30. + */ +@Component +public class ServiceInvoker { + @Autowired + private ApplicationContext context; + + private ObjectMapper objectMapper; + + private Map serviceCacheMap; + + private ServiceInvoker() { + objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + serviceCacheMap = new HashMap<>(); + } + + private static class Cache { + private ServiceCache serviceCache; + private Map methodCacheMap; + + private Cache(Object bean) { + serviceCache = new ServiceCache(); + serviceCache.bean = bean; + + methodCacheMap = new HashMap<>(10); + } + + private Object getBean() { + return serviceCache.bean; + } + + private MethodCache getMethodCache(String methodName) throws NoSuchMethodException, ClassNotFoundException { + MethodCache methodCache = methodCacheMap.get(methodName); + if (null != methodCache) { + return methodCache; + } + + Method method = getMethod(methodName); + if (null == method) { + throw new NoSuchMethodException(); + } + methodCache = new MethodCache(); + methodCacheMap.put(methodName, methodCache); + + methodCache.method = method; + methodCache.returnClazz = method.getReturnType(); + + int paramCount = method.getParameterCount(); + if (0 == paramCount) { + return methodCache; + } + + methodCache.parameterCaches = new ParameterCache[paramCount]; + + ParameterCache parameterCache = null; + + Type[] parameterTypes = method.getGenericParameterTypes(); + Type parameterType = null; + + ParameterizedType parameterizedType = null; + Type[] actualTypeArguments = null; + + for (int i = 0; i < paramCount; i++) { + parameterCache = new ParameterCache(); + methodCache.parameterCaches[i] = parameterCache; + parameterType = parameterTypes[i]; + + if (parameterType instanceof ParameterizedType) { + parameterizedType = (ParameterizedType)parameterType; + parameterCache.clazz = Class.forName(parameterizedType.getRawType().getTypeName()); + actualTypeArguments = parameterizedType.getActualTypeArguments(); + + if (null != actualTypeArguments && 0 < actualTypeArguments.length) { + parameterCache.genericClazzes = new Class[actualTypeArguments.length]; + for (int j = 0; j < actualTypeArguments.length; j++) { + parameterCache.genericClazzes[j] = Class.forName(actualTypeArguments[j].getTypeName()); + } + } + } else { + parameterCache.clazz = Class.forName(parameterType.getTypeName()); + } + } + + return methodCache; + } + + private Method getMethod(String methodName) { + Class clazz = AopUtils.getTargetClass(serviceCache.bean); + Method[] methods = clazz.getMethods(); + + Method targetMethod = null; + for(Method m : methods){ + if (methodName.equals(m.getName())) { + targetMethod = m; + break; + } + } + return targetMethod; + } + + private static class ServiceCache { + private Object bean; + private Map methodCacheMap; + } + private static class MethodCache { + private Method method; + private Class returnClazz; + private ParameterCache[] parameterCaches; + } + private static class ParameterCache { + private Class clazz; + private Class[] genericClazzes; + } + } + + private Cache getServiceCache(String serviceName) { + Cache serviceCache = serviceCacheMap.get(serviceName); + if (null == serviceCache) { + Object bean = context.getBean(serviceName); + serviceCache = new Cache(bean); + serviceCacheMap.put(serviceName, serviceCache); + } + + return serviceCache; + } + + private Object getValue(Cache.ParameterCache parameterCache, String json) throws IOException { + Object result = null; + if (List.class == parameterCache.clazz) { + result = objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(List.class, parameterCache.genericClazzes[0])); + } else if (Map.class == parameterCache.clazz) { + + } else { + result = objectMapper.readValue(json, parameterCache.clazz); + } + + return result; + } + + private Object[] getParameters(Cache.ParameterCache[] parameterCaches, List params) throws IOException { + if (null == parameterCaches || null == params) { + return null; + } + + if (parameterCaches.length != params.size()) { + throw new IllegalArgumentException(); + } + + Object[] result = new Object[parameterCaches.length]; + + for (int i = 0; i < parameterCaches.length; i++) { + result[i] = getValue(parameterCaches[i], params.get(i)); + } + + return result; + } + + public String invoke(String serviceName, String methodName, List params) throws NoSuchMethodException, ClassNotFoundException, IOException, InvocationTargetException, IllegalAccessException { + Cache serviceCache = getServiceCache(serviceName); + Cache.MethodCache methodCache = serviceCache.getMethodCache(methodName); + + Object[] parameters = null; + if (null != methodCache.parameterCaches && 0 < methodCache.parameterCaches.length) { + parameters = getParameters(methodCache.parameterCaches, params); + } + + Object result = methodCache.method.invoke(serviceCache.getBean(), parameters); + + String jsonInString = objectMapper.writeValueAsString(result); + + return jsonInString; + } +} diff --git a/src/test/java/com/loafle/overflow/proxy/ServiceInvokerTest.java b/src/test/java/com/loafle/overflow/proxy/ServiceInvokerTest.java new file mode 100644 index 0000000..448ec26 --- /dev/null +++ b/src/test/java/com/loafle/overflow/proxy/ServiceInvokerTest.java @@ -0,0 +1,44 @@ +package com.loafle.overflow.proxy; + +import com.loafle.overflow.module.target.service.TargetDiscoveryService; +import com.loafle.overflow.spring.AppConfig; +import com.loafle.overflow.spring.JdbcConfiguration; +import com.loafle.overflow.spring.MailConfiguration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by crusader on 17. 6. 30. + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {AppConfig.class, JdbcConfiguration.class, MailConfiguration.class}) +public class ServiceInvokerTest { + @Autowired + private ServiceInvoker serviceInvoker; + + @Test + public void invoke() throws Exception { + + List params = new ArrayList<>(2); + params.add("[{\"id\": 1," + + "\"ip\":2312132112," + + "\"mac\":12312312," + + "\"os\": \"Windows\"," + + "\"target\":true}]"); + params.add("{\"id\": 1," + + "\"ip\":2312132112," + + "\"probeKey\":\"sdfsdfsdfsdfsd\"}"); + + serviceInvoker.invoke("TargetDiscoveryService", "saveAllTarget", params); + + } + +} \ No newline at end of file