View Javadoc
1   /*-
2    * #%L
3    * io.earcam.instrumental.agent.defy
4    * %%
5    * Copyright (C) 2018 earcam
6    * %%
7    * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8    * 
9    * You <b>must</b> choose to accept, in full - any individual or combination of 
10   * the following licenses:
11   * <ul>
12   * 	<li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13   * 	<li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14   * 	<li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15   * 	<li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16   * </ul>
17   * #L%
18   */
19  package io.earcam.instrumental.agent.defy;
20  
21  import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
22  
23  import java.lang.instrument.ClassFileTransformer;
24  import java.lang.instrument.IllegalClassFormatException;
25  import java.security.ProtectionDomain;
26  
27  import org.objectweb.asm.ClassReader;
28  import org.objectweb.asm.ClassVisitor;
29  import org.objectweb.asm.ClassWriter;
30  
31  class RemoveFinalTransformer implements ClassFileTransformer {
32  
33  	private final String[] prefixes;
34  
35  
36  	/**
37  	 * <p>
38  	 * Create a new {@link RemoveFinalTransformer} removing final modifiers
39  	 * from classes matching the {@code prefixes} parameter
40  	 * </p>
41  	 * 
42  	 * @param prefixes
43  	 */
44  	RemoveFinalTransformer(String[] prefixes)
45  	{
46  		this.prefixes = prefixes;
47  	}
48  
49  
50  	@Override
51  	public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)
52  			throws IllegalClassFormatException
53  	{
54  		return prefixMatched(className) ? transform(classfileBuffer) : classfileBuffer;
55  	}
56  
57  
58  	private boolean prefixMatched(String className)
59  	{
60  		for(String prefix : prefixes) {
61  			if(className.startsWith(prefix)) {
62  				return true;
63  			}
64  		}
65  		return false;
66  	}
67  
68  
69  	private byte[] transform(byte[] classfileBuffer)
70  	{
71  		ClassReader cr = new ClassReader(classfileBuffer);
72  		ClassWriter cw = new ClassWriter(cr, COMPUTE_FRAMES);
73  		ClassVisitor cv = new RemoveFinalVisitor(cw);
74  		cr.accept(cv, 0);
75  		return cw.toByteArray();
76  	}
77  }