diff --git a/src/main/java/net/md_5/specialsource/JarInheritanceProvider.java b/src/main/java/net/md_5/specialsource/JarInheritanceProvider.java index a30f370..d249d28 100644 --- a/src/main/java/net/md_5/specialsource/JarInheritanceProvider.java +++ b/src/main/java/net/md_5/specialsource/JarInheritanceProvider.java @@ -5,6 +5,9 @@ import org.objectweb.asm.tree.ClassNode; import java.util.ArrayList; import java.util.List; +/** + * Lookup inheritance from a class given a jar + */ public class JarInheritanceProvider implements IInheritanceProvider { private final Jar self; @@ -14,14 +17,23 @@ public class JarInheritanceProvider implements IInheritanceProvider { @SuppressWarnings("unchecked") // Saddens me to see ASM strip vital info like that public List getParents(String owner) { + System.out.println("jar: owner "+owner); List parents = new ArrayList(); ClassNode node = self.getNode(owner); if (node != null) { for (String iface : (List) node.interfaces) { + System.out.println("jar: add iface="+iface); parents.add(iface); } + System.out.println("jar: add super="+node.superName); parents.add(node.superName); + } else { + System.out.println("jar: nothing for "+owner); } return parents; } + + public String toString() { + return getClass().getSimpleName()+"("+self.file.getName()+")"; + } } diff --git a/src/main/java/net/md_5/specialsource/JarRemapper.java b/src/main/java/net/md_5/specialsource/JarRemapper.java index f44cacc..ab48cd4 100644 --- a/src/main/java/net/md_5/specialsource/JarRemapper.java +++ b/src/main/java/net/md_5/specialsource/JarRemapper.java @@ -33,6 +33,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -47,12 +48,12 @@ import org.objectweb.asm.tree.ClassNode; public class JarRemapper extends Remapper { private static final int CLASS_LEN = ".class".length(); - private final IInheritanceProvider inheritanceProvider; + private final List inheritanceProviders; private final JarMapping jarMapping; - private JarRemapper(JarMapping jarMapping, IInheritanceProvider inheritanceProvider) throws IOException { + private JarRemapper(JarMapping jarMapping, List inheritanceProviders) throws IOException { this.jarMapping = jarMapping; - this.inheritanceProvider = inheritanceProvider; + this.inheritanceProviders = inheritanceProviders; } @Override @@ -96,10 +97,12 @@ public class JarRemapper extends Remapper { String mapped = map.get(key); if (mapped == null) { - for (String parent : inheritanceProvider.getParents(owner)) { - mapped = tryClimb(map, type, parent, name); - if (mapped != null) { - return mapped; + for (IInheritanceProvider inheritanceProvider : inheritanceProviders) { + for (String parent : inheritanceProvider.getParents(owner)) { + mapped = tryClimb(map, type, parent, name); + if (mapped != null) { + return mapped; + } } } } @@ -112,11 +115,15 @@ public class JarRemapper extends Remapper { return mapped == null ? name : mapped; } - public static void renameJar(Jar jar, File target, JarMapping jarMapping) throws IOException { + public static void renameJar(Jar jar, File target, JarMapping jarMapping, boolean live) throws IOException { JarOutputStream out = new JarOutputStream(new FileOutputStream(target)); try { - JarInheritanceProvider jarInheritanceProvider = new JarInheritanceProvider(jar); - JarRemapper self = new JarRemapper(jarMapping, jarInheritanceProvider); + List inheritanceProviders = new ArrayList(); + inheritanceProviders.add(new JarInheritanceProvider(jar)); + if (live) { + inheritanceProviders.add(new RuntimeInheritanceProvider()); + } + JarRemapper self = new JarRemapper(jarMapping, inheritanceProviders); if (jar == null) { return; } diff --git a/src/main/java/net/md_5/specialsource/RuntimeInheritanceProvider.java b/src/main/java/net/md_5/specialsource/RuntimeInheritanceProvider.java new file mode 100644 index 0000000..521cad7 --- /dev/null +++ b/src/main/java/net/md_5/specialsource/RuntimeInheritanceProvider.java @@ -0,0 +1,49 @@ +package net.md_5.specialsource; + +import java.util.List; +import java.util.ArrayList; + +/** + * Lookup class inheritance from classes loaded at runtime + */ +public class RuntimeInheritanceProvider implements IInheritanceProvider { + // TODO: option to transform through a jarRemapper at runtime + + public List getParents(String internalClassName) { + List parents = new ArrayList(); + String sourceClassName = toSourceName(internalClassName); + Class clazz; + try { + clazz = ClassLoader.getSystemClassLoader().loadClass(sourceClassName); // load class without initializing + //clazz = Class.forName(toSourceName(sourceClassName)); // runs static initializers - avoid! + } catch (Throwable t) { + System.out.println("RuntimeInheritanceProvider failed: "+t); + return parents; + } + + for (Class iface : clazz.getInterfaces()) { + parents.add(toInternalName(iface.getName())); + } + + Class superClass = clazz.getSuperclass(); + if (superClass != null) { + parents.add(toInternalName(superClass.getName())); + } + + return parents; + } + + // Convert class name from internal name to source name + public String toSourceName(String className) { + return className.replace('/', '.'); + } + + // .. and vice versa + public String toInternalName(String className) { + return className.replace('.', '/'); + } + + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/src/main/java/net/md_5/specialsource/SpecialSource.java b/src/main/java/net/md_5/specialsource/SpecialSource.java index 3923c00..0edc33a 100644 --- a/src/main/java/net/md_5/specialsource/SpecialSource.java +++ b/src/main/java/net/md_5/specialsource/SpecialSource.java @@ -76,6 +76,8 @@ public class SpecialSource { .withRequiredArg() .withValuesSeparatedBy(','); + acceptsAll(asList("l", "live"), "Enable runtime inheritance lookup"); + acceptsAll(asList("q", "quiet"), "Quiet mode"); acceptsAll(asList("c", "compact"), "Output mapping file in compact format"); } @@ -150,7 +152,7 @@ public class SpecialSource { log("Remapping final jar"); Jar jar3 = Jar.init((File)options.valueOf("in-jar")); - JarRemapper.renameJar(jar3, (File)options.valueOf("out-jar"), jarMapping); + JarRemapper.renameJar(jar3, (File)options.valueOf("out-jar"), jarMapping, options.has("live")); } }