private void visitType(java.lang.reflect.Type type, StringBuilder builder) { if (type instanceof Class) { Class<?> cl = (Class<?>) type; if (cl.isPrimitive()) { builder.append(Type.getType(cl).getDescriptor()); } else { if (cl.isArray()) { builder.append(cl.getName().replace('.', '/')); } else { builder.append('L'); builder.append(cl.getName().replace('.', '/')); builder.append(';'); } } } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; visitNested(parameterizedType.getRawType(), builder); builder.append('<'); for (java.lang.reflect.Type param : parameterizedType.getActualTypeArguments()) { visitType(param, builder); } builder.append(">;"); } else if (type instanceof WildcardType) { WildcardType wildcardType = (WildcardType) type; if (wildcardType.getUpperBounds().length == 1 && wildcardType.getUpperBounds()[0].equals(Object.class)) { if (wildcardType.getLowerBounds().length == 0) { builder.append('*'); return; } } else { for (java.lang.reflect.Type upperType : wildcardType.getUpperBounds()) { builder.append('+'); visitType(upperType, builder); } } for (java.lang.reflect.Type lowerType : wildcardType.getLowerBounds()) { builder.append('-'); visitType(lowerType, builder); } } else if (type instanceof TypeVariable) { TypeVariable<?> typeVar = (TypeVariable) type; builder.append('T'); builder.append(typeVar.getName()); builder.append(';'); } else if (type instanceof GenericArrayType) { GenericArrayType arrayType = (GenericArrayType) type; builder.append('['); visitType(arrayType.getGenericComponentType(), builder); } else { throw new IllegalArgumentException( String.format("Cannot generate signature for %s.", type)); } }
public static Class<?> malform(Class<?> type) throws Exception { ClassReader classReader = new ClassReader(type.getName()); ClassWriter classWriter = new ClassWriter(classReader, 0); classReader.accept(new SignatureMalformer(classWriter), 0); ClassLoader classLoader = new ByteArrayClassLoader( null, Collections.singletonMap(type.getName(), classWriter.toByteArray()), null, ByteArrayClassLoader.PersistenceHandler.MANIFEST, PackageDefinitionStrategy.NoOp.INSTANCE); return classLoader.loadClass(type.getName()); }
private boolean isTransformed(Class clazz, String name, boolean isInterface) { if (isBytemanClass(name) || !isTransformable(name)) { return false; } boolean found = false; List<RuleScript> scripts; if (isInterface) { scripts = scriptRepository.scriptsForInterfaceName(name); } else { scripts = scriptRepository.scriptsForClassName(name); } if (scripts != null) { for (RuleScript script : scripts) { if (!script.hasTransform(clazz)) { found = true; if (isVerbose()) { System.out.println("Retransforming loaded bootstrap class " + clazz.getName()); } break; } } } return found; }
/** * check whether a class should not be considered for transformation * * @param clazz the class to check * @return true if clazz should not be considered for transformation otherwise false */ protected boolean isSkipClass(Class<?> clazz) { if (!inst.isModifiableClass(clazz)) { return true; } // we can safely skip array classes, interfaces and primitive classes if (clazz.isArray()) { return true; } if (clazz.isInterface()) { return true; } if (clazz.isPrimitive()) { return true; } String name = clazz.getName(); if (isBytemanClass(name) || !isTransformable(name)) { return true; } return false; }
public static Class getHelperAdapter(Rule rule, Class helperClass, boolean compileToBytecode) throws CompileException { Class adapterClass; // ok we have to create the adapter class // n.b. we don't bother synchronizing here -- if another rule is racing to create an adapter // in parallel we don't really care about generating two of them -- we can use whichever // one gets installed last try { String helperName = Type.getInternalName(helperClass); String compiledHelperName; // we put the helper in the if (compileToBytecode) { compiledHelperName = helperName + "_HelperAdapter_Compiled_" + nextId(); } else { compiledHelperName = helperName + "_HelperAdapter_Interpreted_" + nextId(); } byte[] classBytes = compileBytes(rule, helperClass, helperName, compiledHelperName, compileToBytecode); String externalName = compiledHelperName.replace('/', '.'); // dump the compiled class bytes if required Transformer.maybeDumpClass(externalName, classBytes); // ensure the class is loaded // think we need to load the generated helper using the class loader of the trigger class ClassLoader loader = rule.getLoader(); adapterClass = loadHelperAdapter(loader, externalName, classBytes); } catch (CompileException ce) { throw ce; } catch (Throwable th) { if (compileToBytecode) { throw new CompileException( "Compiler.createHelperAdapter : exception creating compiled helper adapter for " + helperClass.getName(), th); } else { throw new CompileException( "Compiler.createHelperAdapter : exception creating interpreted helper adapter for " + helperClass.getName(), th); } } return adapterClass; }
private ClassBuilderImpl(Class<T> type) { this.type = type; visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS); typeName = type.getName() + "_Decorated"; generatedType = Type.getType("L" + typeName.replaceAll("\\.", "/") + ";"); superclassType = Type.getType(type); }
@Test public void testSourceName() throws Exception { for (Class<?> type : standardTypes) { if (type.isArray()) { assertThat(describe(type).getActualName(), is(type.getComponentType().getName() + "[]")); } else { assertThat(describe(type).getActualName(), is(type.getName())); } } }
/** * Creates a visitor which will be used as a base class for initiating the visit. It is not * necessary that the class is the superclass, any will do, as long as it can be loaded from a * byte[]. * * @param baseClass * @return */ private ClassReader createClassVisitor(final Class baseClass) { try { String name = baseClass.getName(); String path = name.replace('.', '/') + ".class"; InputStream in = loader.getResourceAsStream(path); return new ClassReader(in); } catch (IOException e) { throw new GroovyRuntimeException( "Unable to generate a proxy for " + baseClass + " from class loader " + loader, e); } }
private void visitNested(java.lang.reflect.Type type, StringBuilder builder) { if (type instanceof Class) { Class<?> cl = (Class<?>) type; if (cl.isPrimitive()) { builder.append(Type.getType(cl).getDescriptor()); } else { builder.append('L'); builder.append(cl.getName().replace('.', '/')); } } else { visitType(type, builder); } }
private String proxyName() { String name = delegateClass != null ? delegateClass.getName() : superClass.getName(); int index = name.lastIndexOf('.'); if (index == -1) return name + pxyCounter.incrementAndGet() + "_groovyProxy"; return name.substring(index + 1, name.length()) + pxyCounter.incrementAndGet() + "_groovyProxy"; }
private void putClassOnStack(MethodVisitor methodVisitor, Class<?> managedTypeClass) { putConstantOnStack(methodVisitor, managedTypeClass.getName()); methodVisitor.visitMethodInsn( INVOKESTATIC, CLASS_INTERNAL_NAME, "forName", FOR_NAME_METHOD_DESCRIPTOR, false); }
protected void injectSetByIndex( ClassWriter classWriter, String targetClassName, List<Field> fields) { MethodVisitor methodVisitor = classWriter.visitMethod( ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, new String[] {getInternalName(ILLEGAL_ACCESS_EXCEPTION.getCanonicalName())}); Boxer boxer = new Boxer(methodVisitor); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ILOAD, 2); int maxStack = 6; Label[] labels = new Label[fields.size()]; Label errorLabel = new Label(); for (int i = 0; i < fields.size(); i++) { labels[i] = new Label(); } methodVisitor.visitTableSwitchInsn(0, labels.length - 1, errorLabel, labels); if (!fields.isEmpty()) { maxStack--; for (int i = 0; i < fields.size(); i++) { Field field = fields.get(i); Class<?> type = field.getType(); Class<?> inputType = Boxer.wrap(type); String fieldDescriptor = Type.getDescriptor(type); String inputPath = getInternalName(inputType.getName()); methodVisitor.visitLabel(labels[i]); if (i == 0) methodVisitor.visitFrame(F_APPEND, 1, new Object[] {targetClassName}, 0, null); else methodVisitor.visitFrame(F_SAME, 0, null, 0, null); if (isPublic(field) && !isFinal(field)) { methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitTypeInsn(CHECKCAST, targetClassName); methodVisitor.visitVarInsn(ALOAD, 3); if (!type.isPrimitive()) { methodVisitor.visitTypeInsn(CHECKCAST, inputPath); } else { boxer.unbox(Type.getType(type)); } methodVisitor.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldDescriptor); } else { injectReflectiveSetter(methodVisitor); } methodVisitor.visitInsn(RETURN); } methodVisitor.visitLabel(errorLabel); methodVisitor.visitFrame(F_SAME, 0, null, 0, null); } injectException(methodVisitor, IllegalAccessException.class); methodVisitor.visitMaxs(maxStack, 4); methodVisitor.visitEnd(); }
public static List<InstantiatorDefinition> extractDefinitions(final Type target) throws IOException { final List<InstantiatorDefinition> constructors = new ArrayList<InstantiatorDefinition>(); final Class<?> targetClass = TypeHelper.toClass(target); ClassLoader cl = targetClass.getClassLoader(); if (cl == null) { cl = ClassLoader.getSystemClassLoader(); } final String fileName = targetClass.getName().replace('.', '/') + ".class"; final InputStream is = cl.getResourceAsStream(fileName); try { if (is == null) { throw new IOException("Cannot find file " + fileName + " in " + cl); } ClassReader classReader = new ClassReader(is); classReader.accept( new ClassVisitor(Opcodes.ASM5) { List<String> genericTypeNames; @Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (signature != null) { genericTypeNames = AsmUtils.extractGenericTypeNames(signature); } else { genericTypeNames = Collections.emptyList(); } super.visit(version, access, name, signature, superName, interfaces); } @Override public MethodVisitor visitMethod( int access, final String methodName, String desc, String signature, String[] exceptions) { final boolean isConstructor = "<init>".equals(methodName); if ((Opcodes.ACC_PUBLIC & access) == Opcodes.ACC_PUBLIC && (isConstructor || ((Opcodes.ACC_STATIC & access) == Opcodes.ACC_STATIC && !desc.endsWith("V")))) { final List<String> descTypes = AsmUtils.extractTypeNames(desc); final List<String> genericTypes; final List<String> names = new ArrayList<String>(); if (signature != null) { genericTypes = AsmUtils.extractTypeNames(signature); } else { genericTypes = descTypes; } if (!isConstructor) { if (descTypes.size() > 0) { try { final Type genericType = AsmUtils.toGenericType( descTypes.get(descTypes.size() - 1), genericTypeNames, target); if (!targetClass.isAssignableFrom(TypeHelper.toClass(genericType))) { return null; } } catch (ClassNotFoundException e) { return null; } } else return null; } return new MethodVisitor(Opcodes.ASM5) { Label firstLabel; Label lastLabel; @Override public void visitLabel(Label label) { if (firstLabel == null) { firstLabel = label; } lastLabel = label; } @Override public void visitLocalVariable( String name, String desc, String signature, Label start, Label end, int index) { if (start.equals(firstLabel) && end.equals(lastLabel) && !"this".equals(name)) { names.add(name); } } @Override public void visitEnd() { try { final List<Parameter> parameters = new ArrayList<Parameter>(); int l = descTypes.size() - (isConstructor ? 0 : 1); for (int i = 0; i < l; i++) { String name = "arg" + i; if (i < names.size()) { name = names.get(i); } parameters.add( createParameter(i, name, descTypes.get(i), genericTypes.get(i))); } final Member executable; if (isConstructor) { executable = targetClass.getDeclaredConstructor(toTypeArray(parameters)); } else { executable = targetClass.getDeclaredMethod(methodName, toTypeArray(parameters)); } constructors.add( new ExecutableInstantiatorDefinition( executable, parameters.toArray(new Parameter[0]))); } catch (Exception e) { ErrorHelper.rethrow(e); } } private Class<?>[] toTypeArray(List<Parameter> parameters) { Class<?>[] types = new Class<?>[parameters.size()]; for (int i = 0; i < types.length; i++) { types[i] = parameters.get(i).getType(); } return types; } private Parameter createParameter( int index, String name, String desc, String signature) { try { Type basicType = AsmUtils.toGenericType(desc, genericTypeNames, target); Type genericType = basicType; if (signature != null) { Type type = AsmUtils.toGenericType(signature, genericTypeNames, target); if (type != null) { genericType = type; } } return new Parameter(index, name, TypeHelper.toClass(basicType), genericType); } catch (ClassNotFoundException e) { throw new Error("Unexpected error " + e, e); } } }; } else { return null; } } }, 0); } finally { try { is.close(); } catch (Exception e) { } } return constructors; }
@Test public void testName() throws Exception { for (Class<?> type : standardTypes) { assertThat(describe(type).getName(), is(type.getName())); } }