All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swak.core.command.SwakMethodProvider Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2015 Netflix, Inc.
 * 

* Licensed 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 *

* 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 com.swak.core.command; import com.google.common.base.Optional; import com.netflix.hystrix.contrib.javanica.utils.FallbackMethod; import com.swak.core.command.annotation.SwakFallback; import com.swak.core.command.exception.SwakFallBackException; import com.swak.core.command.fallback.SwakFallbackMethod; import com.swak.core.interceptor.SwakAnnotationUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import static org.objectweb.asm.Opcodes.*; public final class SwakMethodProvider { public static final Set> FALLBACK_ANNOTATIONS = new LinkedHashSet<>(1); private static final SwakMethodProvider INSTANCE = new SwakMethodProvider(); static { FALLBACK_ANNOTATIONS.add(SwakFallback.class); } private Map cache = new ConcurrentHashMap(); private SwakMethodProvider() { } public static SwakMethodProvider getInstance() { return INSTANCE; } private static int getParameterCount(String desc) { return parseParams(desc).length; } private static String[] parseParams(String desc) { String params = desc.split("\\)")[0].replace("(", ""); if (params.length() == 0) { return new String[0]; } return params.split(";"); } public SwakFallbackMethod getFallbackMethod(Class type, Method commandMethod) { return getFallbackMethod(type, commandMethod, false); } /** * Gets fallback method for command method. * * @param type type * @param commandMethod the command method. in the essence it can be a fallback * method annotated with HystrixCommand annotation that has * a fallback as well. * @param extended true if the given commandMethod was derived using * additional parameter, otherwise - false * @return new instance of {@link FallbackMethod} or * {@link FallbackMethod#ABSENT} if there is no suitable fallback method * for the given command */ public SwakFallbackMethod getFallbackMethod(Class type, Method commandMethod, boolean extended) { SwakFallback swakFallback = null; Collection fallbackColls = SwakAnnotationUtils.computeOperations(commandMethod, type, FALLBACK_ANNOTATIONS); if (CollectionUtils.isEmpty(fallbackColls)) { return SwakFallbackMethod.ABSENT; } swakFallback = (SwakFallback) fallbackColls.iterator().next(); if (swakFallback == null || StringUtils.isBlank(swakFallback.fallbackMethod())) { return SwakFallbackMethod.ABSENT; } Class[] parameterTypes = commandMethod.getParameterTypes(); if (extended && parameterTypes[parameterTypes.length - 1] == Throwable.class) { parameterTypes = ArrayUtils.remove(parameterTypes, parameterTypes.length - 1); } Class[] exParameterTypes = Arrays.copyOf(parameterTypes, parameterTypes.length + 1); exParameterTypes[parameterTypes.length] = Throwable.class; Optional exFallbackMethod = getMethod(type, swakFallback.fallbackMethod(), exParameterTypes); Optional fMethod = getMethod(type, swakFallback.fallbackMethod(), parameterTypes); Method method = exFallbackMethod.or(fMethod).orNull(); if (method == null) { throw new SwakFallBackException("fallback method wasn't found: " + swakFallback.fallbackMethod() + "(" + Arrays.toString(parameterTypes) + ")"); } return new SwakFallbackMethod(method, swakFallback.fallbackMethod(), exFallbackMethod.isPresent(), swakFallback); } public Optional getMethod(Class type, String name, Class... parameterTypes) { Method[] methods = type.getDeclaredMethods(); for (Method method : methods) { if (method.getName().equals(name) && Arrays.equals(method.getParameterTypes(), parameterTypes)) { return Optional.of(method); } } Class superClass = type.getSuperclass(); if (superClass != null && !superClass.equals(Object.class)) { return getMethod(superClass, name, parameterTypes); } else { return Optional.absent(); } } /** * Finds generic method for the given bridge method. * * @param bridgeMethod the bridge method * @param aClass the type where the bridge method is declared * @return generic method * @throws IOException * @throws NoSuchMethodException * @throws ClassNotFoundException */ public Method unbride(final Method bridgeMethod, Class aClass) throws IOException, NoSuchMethodException, ClassNotFoundException { if (bridgeMethod.isBridge() && bridgeMethod.isSynthetic()) { if (cache.containsKey(bridgeMethod)) { return cache.get(bridgeMethod); } ClassReader classReader = new ClassReader(aClass.getName()); final MethodSignature methodSignature = new MethodSignature(); classReader.accept(new ClassVisitor(ASM5) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { boolean bridge = (access & ACC_BRIDGE) != 0 && (access & ACC_SYNTHETIC) != 0; if (bridge && bridgeMethod.getName().equals(name) && getParameterCount(desc) == bridgeMethod.getParameterTypes().length) { return new MethodFinder(methodSignature); } return super.visitMethod(access, name, desc, signature, exceptions); } }, 0); Method method = aClass.getDeclaredMethod(methodSignature.name, methodSignature.getParameterTypes()); cache.put(bridgeMethod, method); return method; } else { return bridgeMethod; } } private static class MethodSignature { String name; String desc; public Class[] getParameterTypes() throws ClassNotFoundException { if (desc == null) { return new Class[0]; } String[] params = parseParams(desc); Class[] parameterTypes = new Class[params.length]; for (int i = 0; i < params.length; i++) { String arg = params[i].substring(1).replace("/", "."); parameterTypes[i] = Class.forName(arg); } return parameterTypes; } } private static class MethodFinder extends MethodVisitor { private MethodSignature methodSignature; public MethodFinder(MethodSignature methodSignature) { super(ASM5); this.methodSignature = methodSignature; } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { methodSignature.name = name; methodSignature.desc = desc; super.visitMethodInsn(opcode, owner, name, desc, itf); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy