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

net.amygdalum.testrecorder.AllLambdasSerializableTransformer Maven / Gradle / Ivy

package net.amygdalum.testrecorder;

import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.Collection;
import java.util.Iterator;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;

import net.amygdalum.testrecorder.util.AttachableClassFileTransformer;
import net.amygdalum.testrecorder.util.Logger;

public class AllLambdasSerializableTransformer extends AttachableClassFileTransformer implements ClassFileTransformer {

	private static final int IS_SERIALIZABLE_PARAMETER_LOCAL = 7;

	public AllLambdasSerializableTransformer() {
	}
	
	@Override
	public Collection> filterClassesToRetransform(Class[] loaded) {
		for (Class clazz : loaded) {
			if ("java.lang.invoke.InnerClassLambdaMetafactory".equals(clazz.getName())) {
				return singleton(clazz);
			}
		}
		return emptyList();
	}

	@Override
	public Collection> getClassesToRetransform() {
		try {
			return singletonList(Class.forName("java.lang.invoke.InnerClassLambdaMetafactory"));
		} catch (ClassNotFoundException e) {
			return emptyList();
		}
	}

	@Override
	public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
		boolean aquired = lock.acquire();
		if (!aquired) {
			return null;
		}
		try {
			if (className != null && className.equals("java/lang/invoke/InnerClassLambdaMetafactory")) {
				ClassReader cr = new ClassReader(classfileBuffer);
				ClassNode classNode = new ClassNode();

				cr.accept(classNode, 0);
				classNode.methods.stream()
					.filter(method -> "".equals(method.name))
					.findFirst()
					.ifPresent(method -> {
						Optional serialized = findIsSerializeableLocalVariable(method);
						serialized.ifPresent(val -> method.instructions.set(val, new InsnNode(Opcodes.ICONST_1)));
					});

				ClassWriter out = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
				classNode.accept(out);
				return out.toByteArray();
			}
			return null;
		} catch (Throwable e) {
			Logger.error("transformation error: ", e);
			return null;
		} finally {
			lock.release();
		}

	}

	private Optional findIsSerializeableLocalVariable(MethodNode method) {
		return stream(method.instructions.iterator())
			.filter(node -> node instanceof VarInsnNode)
			.map(node -> (VarInsnNode) node)
			.filter(node -> node.getOpcode() == Opcodes.ILOAD)
			.filter(node -> node.var == IS_SERIALIZABLE_PARAMETER_LOCAL)
			.findFirst();
	}

	private  Stream stream(Iterator iterator) {
		Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
		return StreamSupport.stream(spliterator, false);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy