use of org.apache.xbean.asm6.ClassWriter in project component-runtime by Talend.
the class ProxyGenerator method createConstructor.
private String createConstructor(final ClassWriter cw, final Class<?> classToProxy, final String classFileName, final String proxyClassFileName, final Constructor<?> constructor, final boolean withInterceptors) {
try {
Constructor superDefaultCt;
String parentClassFileName;
String[] exceptions = null;
if (classToProxy.isInterface()) {
parentClassFileName = Type.getInternalName(Object.class);
superDefaultCt = Object.class.getConstructor();
} else {
parentClassFileName = classFileName;
if (constructor == null) {
superDefaultCt = classToProxy.getConstructor();
} else {
superDefaultCt = constructor;
Class<?>[] exceptionTypes = constructor.getExceptionTypes();
exceptions = exceptionTypes.length == 0 ? null : new String[exceptionTypes.length];
for (int i = 0; i < exceptionTypes.length; i++) {
exceptions[i] = Type.getInternalName(exceptionTypes[i]);
}
}
}
final String descriptor = Type.getConstructorDescriptor(superDefaultCt);
final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", descriptor, null, exceptions);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
if (constructor != null) {
for (int i = 1; i <= constructor.getParameterTypes().length; i++) {
mv.visitVarInsn(ALOAD, i);
}
}
mv.visitMethodInsn(INVOKESPECIAL, parentClassFileName, "<init>", descriptor, false);
if (withInterceptors) {
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ACONST_NULL);
mv.visitFieldInsn(PUTFIELD, proxyClassFileName, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class));
}
mv.visitInsn(RETURN);
mv.visitMaxs(-1, -1);
mv.visitEnd();
return parentClassFileName;
} catch (final NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
use of org.apache.xbean.asm6.ClassWriter in project component-runtime by Talend.
the class ProxyGenerator method generateProxy.
public Class<?> generateProxy(final ClassLoader loader, final Class<?> classToProxy, final String plugin, final String key) {
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final String proxyClassName = fixPreservedPackages((classToProxy.getSigners() != null ? getSignedClassProxyName(classToProxy) : classToProxy.getName()) + "$$TalendServiceProxy");
final String classFileName = proxyClassName.replace('.', '/');
final String[] interfaceNames = { Type.getInternalName(Serializable.class) };
final String superClassName = Type.getInternalName(classToProxy);
cw.visit(findJavaVersion(classToProxy), ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC, classFileName, null, superClassName, interfaceNames);
cw.visitSource(classFileName + ".java", null);
if (!Serializable.class.isAssignableFrom(classToProxy)) {
try {
classToProxy.getMethod("writeReplace");
} catch (final NoSuchMethodException e) {
createSerialisation(cw, plugin, key);
}
}
final boolean hasInterceptors = hasInterceptors(classToProxy);
if (hasInterceptors) {
cw.visitField(ACC_PRIVATE, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class), null, null).visitEnd();
cw.visitField(ACC_PRIVATE | ACC_STATIC, FIELD_INTERCEPTED_METHODS, Type.getDescriptor(Method[].class), null, null).visitEnd();
}
createConstructor(cw, classToProxy, superClassName, classFileName, Stream.of(classToProxy.getDeclaredConstructors()).filter(c -> {
final int modifiers = c.getModifiers();
return Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers);
}).sorted((o1, o2) -> {
// prefer public constructor and then the smallest parameter count
final int mod1 = o1.getModifiers();
final int mod2 = o2.getModifiers();
if (Modifier.isProtected(mod1) && !Modifier.isPublic(mod2)) {
return 1;
}
if (Modifier.isProtected(mod2) && !Modifier.isPublic(mod1)) {
return -1;
}
return o1.getParameterCount() - o2.getParameterCount();
}).findFirst().orElseThrow(() -> new IllegalArgumentException(classToProxy + " has no default constructor, put at least a protected one")), hasInterceptors);
final Method[] interceptedMethods;
if (hasInterceptors) {
final Collection<Annotation> globalInterceptors = Stream.of(classToProxy.getAnnotations()).filter(this::isInterceptor).collect(toList());
final AtomicInteger methodIndex = new AtomicInteger();
interceptedMethods = Stream.of(classToProxy.getMethods()).filter(m -> !"<init>".equals(m.getName()) && (!globalInterceptors.isEmpty() || Stream.of(m.getAnnotations()).anyMatch(this::isInterceptor))).peek(method -> delegateMethod(cw, method, classFileName, methodIndex.getAndIncrement())).toArray(Method[]::new);
} else {
interceptedMethods = null;
}
final Class<Object> objectClass = Unsafes.defineAndLoadClass(loader, proxyClassName, cw.toByteArray());
if (hasInterceptors) {
try {
final Field interceptedMethodsField = objectClass.getDeclaredField(FIELD_INTERCEPTED_METHODS);
interceptedMethodsField.setAccessible(true);
interceptedMethodsField.set(null, interceptedMethods);
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
return objectClass;
}
use of org.apache.xbean.asm6.ClassWriter in project component-runtime by Talend.
the class ProxyGenerator method delegateMethod.
private void delegateMethod(final ClassWriter cw, final Method method, final String proxyClassFileName, final int methodIndex) {
final Class<?> returnType = method.getReturnType();
final Class<?>[] parameterTypes = method.getParameterTypes();
final Class<?>[] exceptionTypes = method.getExceptionTypes();
final int modifiers = method.getModifiers();
if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) {
throw new IllegalStateException("It's not possible to proxy a final or static method: " + method.getDeclaringClass().getName() + " " + method.getName());
}
// push the method definition
int modifier = modifiers & (ACC_PUBLIC | ACC_PROTECTED | ACC_VARARGS);
MethodVisitor mv = cw.visitMethod(modifier, method.getName(), Type.getMethodDescriptor(method), null, null);
mv.visitCode();
// push try/catch block, to catch declared exceptions, and to catch java.lang.Throwable
final Label l0 = new Label();
final Label l1 = new Label();
final Label l2 = new Label();
if (exceptionTypes.length > 0) {
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/reflect/InvocationTargetException");
}
// push try code
mv.visitLabel(l0);
final String classNameToOverride = method.getDeclaringClass().getName().replace('.', '/');
mv.visitLdcInsn(Type.getType("L" + classNameToOverride + ";"));
// the following code generates the bytecode for this line of Java:
// Method method = <proxy>.class.getMethod("add", new Class[] { <array of function argument classes> });
// get the method name to invoke, and push to stack
mv.visitLdcInsn(method.getName());
// create the Class[]
createArrayDefinition(mv, parameterTypes.length, Class.class);
int length = 1;
// push parameters into array
for (int i = 0; i < parameterTypes.length; i++) {
// keep copy of array on stack
mv.visitInsn(DUP);
Class<?> parameterType = parameterTypes[i];
// push number onto stack
pushIntOntoStack(mv, i);
if (parameterType.isPrimitive()) {
String wrapperType = getWrapperType(parameterType);
mv.visitFieldInsn(GETSTATIC, wrapperType, "TYPE", "Ljava/lang/Class;");
} else {
mv.visitLdcInsn(Type.getType(parameterType));
}
mv.visitInsn(AASTORE);
if (Long.TYPE.equals(parameterType) || Double.TYPE.equals(parameterType)) {
length += 2;
} else {
length++;
}
}
// the following code generates bytecode equivalent to:
// return ((<returntype>) invocationHandler.invoke(this, {methodIndex}, new Object[] { <function arguments
// }))[.<primitive>Value()];
final Label l4 = new Label();
mv.visitLabel(l4);
mv.visitVarInsn(ALOAD, 0);
// get the invocationHandler field from this class
mv.visitFieldInsn(GETFIELD, proxyClassFileName, FIELD_INTERCEPTOR_HANDLER, Type.getDescriptor(InterceptorHandler.class));
// add the Method from the static array as first parameter
mv.visitFieldInsn(GETSTATIC, proxyClassFileName, FIELD_INTERCEPTED_METHODS, Type.getDescriptor(Method[].class));
// push the methodIndex of the current method
if (methodIndex < 128) {
mv.visitIntInsn(BIPUSH, methodIndex);
} else if (methodIndex < 32267) {
// for methods > 127 we need to push a short number as index
mv.visitIntInsn(SIPUSH, methodIndex);
} else {
throw new IllegalStateException("Sorry, we only support Classes with 2^15 methods...");
}
// and now load the Method from the array
mv.visitInsn(AALOAD);
// prepare the parameter array as Object[] and store it on the stack
pushMethodParameterArray(mv, parameterTypes);
// invoke the invocationHandler
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(InterceptorHandler.class), "invoke", "(Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true);
// cast the result
mv.visitTypeInsn(CHECKCAST, getCastType(returnType));
if (returnType.isPrimitive() && (!Void.TYPE.equals(returnType))) {
// get the primitive value
mv.visitMethodInsn(INVOKEVIRTUAL, getWrapperType(returnType), getPrimitiveMethod(returnType), "()" + Type.getDescriptor(returnType), false);
}
// push return
mv.visitLabel(l1);
if (!Void.TYPE.equals(returnType)) {
mv.visitInsn(getReturnInsn(returnType));
} else {
mv.visitInsn(POP);
mv.visitInsn(RETURN);
}
// catch InvocationTargetException
if (exceptionTypes.length > 0) {
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, length);
Label l5 = new Label();
mv.visitLabel(l5);
for (int i = 0; i < exceptionTypes.length; i++) {
Class<?> exceptionType = exceptionTypes[i];
mv.visitLdcInsn(Type.getType("L" + exceptionType.getCanonicalName().replace('.', '/') + ";"));
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false);
final Label l6 = new Label();
mv.visitJumpInsn(IFEQ, l6);
final Label l7 = new Label();
mv.visitLabel(l7);
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/InvocationTargetException", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitTypeInsn(CHECKCAST, getCastType(exceptionType));
mv.visitInsn(ATHROW);
mv.visitLabel(l6);
if (i == (exceptionTypes.length - 1)) {
mv.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, length);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
}
}
}
// finish this method
mv.visitMaxs(0, 0);
mv.visitEnd();
}
use of org.apache.xbean.asm6.ClassWriter in project component-runtime by Talend.
the class RepositoryModelBuilderTest method createChainPlugin.
private File createChainPlugin(final File dir, final String plugin) {
final File target = new File(dir, plugin);
try (final JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(target))) {
final String packageName = toPackage(target.getParentFile().getParentFile().getName()).replace(".", "/");
final String sourcePackage = "org/talend/test";
final String fromPack = sourcePackage.replace('/', '.');
final String toPack = packageName.replace('.', '/');
final File root = new File(jarLocation(getClass()), sourcePackage);
ofNullable(root.listFiles()).map(Stream::of).orElseGet(Stream::empty).filter(c -> c.getName().endsWith(".class")).forEach(clazz -> {
try (final InputStream is = new FileInputStream(clazz)) {
final ClassReader reader = new ClassReader(is);
final ClassWriter writer = new ClassWriter(COMPUTE_FRAMES);
reader.accept(new ClassRemapper(writer, new Remapper() {
@Override
public String map(final String key) {
return key.replace(sourcePackage, toPack).replace(fromPack, packageName);
}
}), EXPAND_FRAMES);
outputStream.putNextEntry(new JarEntry(toPack + '/' + clazz.getName()));
outputStream.write(writer.toByteArray());
} catch (final IOException e) {
fail(e.getMessage());
}
});
} catch (final IOException e) {
throw new IllegalStateException(e);
}
return target;
}
use of org.apache.xbean.asm6.ClassWriter in project tomee by apache.
the class ValidationGenerator method generate.
public byte[] generate() throws ProxyGenerationException {
generatedMethods.clear();
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
final String generatedClassName = getName().replace('.', '/');
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, generatedClassName, null, "java/lang/Object", null);
{
// public constructor
final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
generateMethods(cw);
/**
* Read all parent classes and copy the public methods we need
* into our new class.
*/
Class current = clazz;
while (current != null && !current.equals(Object.class)) {
try {
final ClassReader classReader = new ClassReader(DynamicSubclass.readClassFile(current));
classReader.accept(new CopyMethodAnnotations(), ClassReader.SKIP_CODE);
} catch (final IOException e) {
throw new ProxyGenerationException(e);
}
current = current.getSuperclass();
}
return cw.toByteArray();
}
Aggregations