pax_global_header 0000666 0000000 0000000 00000000064 13247547534 0014530 g ustar 00root root 0000000 0000000 52 comment=0724889e8adc62258b610435b76793d4a5c10a40
bridger-1.5.Final/ 0000775 0000000 0000000 00000000000 13247547534 0014043 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/.gitignore 0000664 0000000 0000000 00000000076 13247547534 0016036 0 ustar 00root root 0000000 0000000 .project
.classpath
.settings
*.iml
target
.idea
*.ipr
*~
out
bridger-1.5.Final/README.md 0000664 0000000 0000000 00000004065 13247547534 0015327 0 ustar 00root root 0000000 0000000 bridger
=======
A bytecode mangler for creating your own synthetic bridge methods, which allows more dramatic source code changes while still maintaining binary compatibility. And probably some other ugly tricks too.
Usage: Source code
------------------
In your Java source, create your bridge methods with `$$bridge` in the name. Everything before the `$$bridge` is retained, everything including and after it is discarded. The methods will additionally be tagged as `ACC_BRIDGE` and `ACC_SYNTHETIC`.
Usage: Maven
------------
Add a snippet like this to your pom.xml:
org.jboss.bridger
bridger
1.5.Final
weave
process-classes
transform
weave-tests
process-test-classes
transform
${project.build.testOutputDirectory}
_Note that a separate execution is needed if you want your test classes to be transformed._
Usage: Command Line
-------------------
Execute like this:
java -classpath path/to/bridger.jar:path/to/asm-6.0.jar org.jboss.bridger.Bridger path/of/class/files/
The class files will be transformed in place.
bridger-1.5.Final/pom.xml 0000664 0000000 0000000 00000016204 13247547534 0015363 0 ustar 00root root 0000000 0000000
4.0.0
org.jboss.bridger
bridger
1.5.Final
maven-plugin
org.jboss
jboss-parent
23
4.11
2.2.1
3.0.5
3.0.5
3.2
3.5.1
3.2
2.6
1.1
3.0.10
1.7
1.7
org.apache.maven.plugins
maven-plugin-plugin
${version.org.apache.maven.plugins.plugin}
maven-jar-plugin
org.jboss.bridger.Bridger
${project.version}
${project.artifactId}
org.apache.maven.plugins
maven-site-plugin
${version.org.apache.maven.plugins.site-plugin}
false
org.apache.maven.plugins
maven-plugin-plugin
${version.org.apache.maven.plugins.plugin}
true
org.ow2.asm
asm
5.2
default-descriptor
descriptor
help-goal
helpmojo
org.jboss.bridger
org.ow2.asm
asm
6.0
org.apache.maven
maven-plugin-api
${version.org.apache.maven.plugin-api}
org.apache.maven
maven-project
${version.org.apache.maven.maven-plugin}
org.apache.maven.shared
maven-filtering
${version.org.apache.maven.shared.maven-filtering}
org.apache.maven.plugin-tools
maven-plugin-annotations
${version.org.apache.maven.plugin-tools}
org.codehaus.plexus
plexus-utils
${version.org.codehaus.plexus.plexus-utils}
org.apache.maven
maven-settings
${version.org.apache.maven.maven-settings}
bridger-1.5.Final/src/ 0000775 0000000 0000000 00000000000 13247547534 0014632 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/src/main/ 0000775 0000000 0000000 00000000000 13247547534 0015556 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/src/main/java/ 0000775 0000000 0000000 00000000000 13247547534 0016477 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/src/main/java/org/ 0000775 0000000 0000000 00000000000 13247547534 0017266 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/src/main/java/org/jboss/ 0000775 0000000 0000000 00000000000 13247547534 0020406 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/src/main/java/org/jboss/bridger/ 0000775 0000000 0000000 00000000000 13247547534 0022024 5 ustar 00root root 0000000 0000000 bridger-1.5.Final/src/main/java/org/jboss/bridger/Bridger.java 0000664 0000000 0000000 00000017425 13247547534 0024256 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2014, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.bridger;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.concurrent.atomic.AtomicInteger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* @author David M. Lloyd
*/
public final class Bridger implements ClassFileTransformer {
private final AtomicInteger transformedMethodCount = new AtomicInteger();
private final AtomicInteger transformedMethodCallCount = new AtomicInteger();
public Bridger() {
}
/**
* Translate all {@code .class} files in the given list of files and directories.
*
* @param args the file and directory names
*/
public static void main(String[] args) {
final Bridger bridger = new Bridger();
bridger.transformRecursive(args);
System.out.printf("Translated %d methods and %d method calls%n", bridger.getTransformedMethodCount(), bridger.getTransformedMethodCallCount());
}
/**
* Translate all {@code .class} files in the given list of files and directories.
*
* @param names the file and directory names
*/
public void transformRecursive(String... names) {
final File[] files = new File[names.length];
for (int i = 0; i < names.length; i++) {
files[i] = new File(names[i]);
}
transformRecursive(files);
}
/**
* Translate all {@code .class} files in the given list of files and directories.
*
* @param files the files and directories
*/
public void transformRecursive(File... files) {
for (File file : files) {
if (file.isDirectory()) {
transformRecursive(file.listFiles());
} else if (file.getName().endsWith(".class")) {
try {
transform(new RandomAccessFile(file, "rw"));
} catch (Exception e) {
System.out.println("Failed to transform " + file + ": " + e);
}
}
// else ignore
}
}
public byte[] transform(final ClassLoader loader, final String className, final Class> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
ClassWriter classWriter = new ClassWriter(0);
final ClassReader classReader = new ClassReader(classfileBuffer);
doAccept(classWriter, classReader);
return classWriter.toByteArray();
}
public byte[] transform(final InputStream input) throws IllegalClassFormatException, IOException {
ClassWriter classWriter = new ClassWriter(0);
final ClassReader classReader = new ClassReader(input);
doAccept(classWriter, classReader);
return classWriter.toByteArray();
}
public int getTransformedMethodCount() {
return transformedMethodCount.get();
}
public int getTransformedMethodCallCount() {
return transformedMethodCallCount.get();
}
private void doAccept(final ClassWriter classWriter, final ClassReader classReader) throws IllegalClassFormatException {
try {
classReader.accept(new TranslatingClassVisitor(classWriter), 0);
} catch (RuntimeException e) {
final Throwable cause = e.getCause();
if (cause instanceof IllegalClassFormatException) {
throw (IllegalClassFormatException) cause;
}
throw e;
}
}
public void transform(final InputStream input, final OutputStream output) throws IllegalClassFormatException, IOException {
output.write(transform(input));
}
public void transform(final RandomAccessFile file) throws IllegalClassFormatException, IOException {
try {
file.seek(0);
try (InputStream is = new FileInputStream(file.getFD())) {
final byte[] bytes = transform(is);
file.seek(0);
file.write(bytes);
file.setLength(bytes.length);
}
file.close();
} finally {
safeClose(file);
}
}
private static void safeClose(final Closeable closeable) {
if (closeable != null) try {
closeable.close();
} catch (Throwable ignored) {}
}
private class TranslatingClassVisitor extends ClassVisitor {
public TranslatingClassVisitor(final ClassWriter classWriter) {
super(Opcodes.ASM4, classWriter);
}
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
final MethodVisitor defaultVisitor;
final int idx = name.indexOf("$$bridge");
if (idx != -1) {
transformedMethodCount.getAndIncrement();
defaultVisitor = super.visitMethod(access | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC, name.substring(0, idx), desc, signature, exceptions);
} else {
defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions);
}
return new MethodVisitor(Opcodes.ASM5, defaultVisitor) {
public void visitInvokeDynamicInsn(final String name, final String desc, final Handle bsm, final Object... bsmArgs) {
final int idx = name.indexOf("$$bridge");
if (idx != -1) {
transformedMethodCallCount.getAndIncrement();
final String realName = name.substring(0, idx);
super.visitInvokeDynamicInsn(realName, desc, bsm, bsmArgs);
} else {
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
}
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) {
final int idx = name.indexOf("$$bridge");
if (idx != -1) {
transformedMethodCallCount.getAndIncrement();
final String realName = name.substring(0, idx);
super.visitMethodInsn(opcode, owner, realName, desc, itf);
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
};
}
}
} bridger-1.5.Final/src/main/java/org/jboss/bridger/BridgerMojo.java 0000664 0000000 0000000 00000007624 13247547534 0025103 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
* Copyright 2014, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.bridger;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.DirectoryScanner;
/**
* A plugin that translates bridge methods.
*
* @author James R. Perkins
*/
@Mojo(name = "transform", defaultPhase = LifecyclePhase.PROCESS_CLASSES)
public class BridgerMojo extends AbstractMojo {
/**
* The output directory where resources should be processed
*/
@Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
private File outputDirectory;
/**
* File patterns to include when processing
*/
@Parameter(property = "bridger.excludes")
private String[] excludes;
/**
* File patterns to exclude when processing
*/
@Parameter(defaultValue = "**/*.class", property = "bridger.includes")
private String[] includes;
@Parameter(defaultValue = "false", property = "bridger.transform.skip")
private boolean skip;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
final Log log = getLog();
if (skip) {
log.info("Skipping bridger transform");
} else {
final Bridger bridger = new Bridger();
final File[] files = getFiles();
if (log.isDebugEnabled()) {
final String newLine = String.format("%n\t");
final StringBuilder sb = new StringBuilder("Transforming Files:");
sb.append(newLine);
for (File file : files) {
sb.append(file.getAbsolutePath()).append(newLine);
}
log.debug(sb);
}
bridger.transformRecursive(files);
log.info(String.format("Translated %d methods and %d method calls%n", bridger.getTransformedMethodCount(), bridger.getTransformedMethodCallCount()));
}
}
private File[] getFiles() {
final List result = new ArrayList();
final DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(outputDirectory);
scanner.setIncludes(includes);
scanner.setExcludes(excludes);
scanner.scan();
for (String filename : scanner.getIncludedFiles()) {
// Only class files
final File targetFile = new File(outputDirectory, filename);
if (targetFile.exists()) {
result.add(targetFile.getAbsoluteFile());
}
}
return result.toArray(new File[result.size()]);
}
}