in modules/normalizer/src/main/java/org/apache/commons/weaver/normalizer/Normalizer.java [510:600]
private String copy(final Pair<String, String> key, final ClassWrapper classWrapper) throws IOException {
env.debug("Copying %s to %s", key, targetPackage);
final MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (final NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
md5.update(key.getLeft().getBytes(StandardCharsets.UTF_8));
md5.update(key.getRight().getBytes(StandardCharsets.UTF_8));
final long digest = Conversion.byteArrayToLong(md5.digest(), 0, 0L, 0, Long.SIZE / Byte.SIZE);
final String result = MessageFormat.format("{0}/$normalized{1,number,0;_0}", targetPackage, digest);
env.debug("Copying class %s to %s", classWrapper.wrapped.getName(), result);
try (InputStream bytecode = env.getClassfile(classWrapper.wrapped).getInputStream()) {
final ClassReader reader = new ClassReader(bytecode);
final ClassVisitor writeClass = new WriteClass();
// we're doing most of this by hand; we only read the original class to hijack signature, ctor exceptions,
// etc.:
reader.accept(new ClassVisitor(ASM_VERSION) {
Type supertype;
@Override
@SuppressWarnings("PMD.UseVarargs") //overridden method
public void visit(final int version, final int access, final String name, final String signature,
final String superName, final String[] interfaces) {
supertype = Type.getObjectType(superName);
writeClass.visit(version, Opcodes.ACC_PUBLIC, result, signature, superName, interfaces);
visitAnnotation(Type.getType(Marker.class).getDescriptor(), false);
}
@Override
@SuppressWarnings("PMD.UseVarargs") //overridden method
public MethodVisitor visitMethod(final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
if (INIT.equals(name)) {
final Method staticCtor = new Method(INIT, key.getRight());
final Type[] argumentTypes = staticCtor.getArgumentTypes();
final Type[] exceptionTypes = toObjectTypes(exceptions);
{
final GeneratorAdapter mgen =
new GeneratorAdapter(Opcodes.ACC_PUBLIC, staticCtor, signature, exceptionTypes,
writeClass);
mgen.visitCode();
mgen.loadThis();
for (int i = 0; i < argumentTypes.length; i++) {
mgen.loadArg(i);
}
mgen.invokeConstructor(supertype, staticCtor);
mgen.returnValue();
mgen.endMethod();
}
/*
* now declare a dummy constructor that will match, and discard,
* any originally inner-class bound constructor i.e. that set up a this$0 field.
* By doing this we can avoid playing with the stack that originally
* invoked such a constructor and simply rewrite the method
*/
{
final Method instanceCtor =
new Method(INIT, Type.VOID_TYPE, ArrayUtils.insert(0, argumentTypes, OBJECT_TYPE));
final GeneratorAdapter mgen =
new GeneratorAdapter(Opcodes.ACC_PUBLIC, instanceCtor, signature, exceptionTypes,
writeClass);
mgen.visitCode();
mgen.loadThis();
for (int i = 0; i < argumentTypes.length; i++) {
mgen.loadArg(i + 1);
}
mgen.invokeConstructor(supertype, staticCtor);
mgen.returnValue();
mgen.endMethod();
}
}
return null;
}
@Override
public void visitEnd() {
writeClass.visitEnd();
}
}, 0);
}
return result;
}