001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.transformer;
032:
033: import java.util.*;
034: import net.sf.retrotranslator.runtime.asm.*;
035: import static net.sf.retrotranslator.runtime.asm.Opcodes.*;
036: import net.sf.retrotranslator.runtime.impl.EmptyVisitor;
037:
038: /**
039: * @author Taras Puchko
040: */
041: class MirandaMethodsVisitor extends ClassAdapter {
042:
043: private final ReplacementLocator locator;
044: private final NameTranslator translator;
045:
046: public MirandaMethodsVisitor(ClassVisitor visitor,
047: ReplacementLocator locator) {
048: super (visitor);
049: this .locator = locator;
050: this .translator = locator.getTranslator();
051: }
052:
053: public void visit(int version, int access, String name,
054: String signature, String super Name, String[] interfaces) {
055: super .visit(version, access, name, signature, super Name,
056: interfaces);
057: if ((access & (ACC_ABSTRACT | ACC_INTERFACE)) == ACC_ABSTRACT) {
058: addMirandaMethods(name, super Name, interfaces);
059: }
060: }
061:
062: private void addMirandaMethods(String name, String super Name,
063: String[] interfaces) {
064: if (interfaces == null) {
065: return;
066: }
067: Set<InheritedMethod> methods = new LinkedHashSet<InheritedMethod>();
068: for (String anInterface : interfaces) {
069: methods.addAll(getMethods(anInterface, true));
070: }
071: methods.removeAll(getMethods(super Name, true));
072: methods.removeAll(getMethods(name, false));
073: for (InheritedMethod method : methods) {
074: MethodVisitor visitor = cv.visitMethod(ACC_PUBLIC
075: | ACC_ABSTRACT | ACC_SYNTHETIC, method.name,
076: method.desc, null, method.exceptions);
077: visitor.visitEnd();
078: }
079: }
080:
081: private Set<InheritedMethod> getMethods(String className,
082: boolean recursive) {
083: String uniqueTypeName = locator.getUniqueTypeName(className);
084: Set<InheritedMethod> methods = new LinkedHashSet<InheritedMethod>();
085: ClassReader classReader = locator.getEnvironment()
086: .findClassReader(uniqueTypeName);
087: if (classReader == null) {
088: return methods;
089: }
090: MethodCollector collector = new MethodCollector(methods);
091: classReader.accept(collector, true);
092: if (recursive) {
093: if (collector.super Name != null) {
094: methods.addAll(getMethods(collector.super Name, true));
095: }
096: if (collector.interfaces != null) {
097: for (String anInterface : collector.interfaces) {
098: methods.addAll(getMethods(anInterface, true));
099: }
100: }
101: }
102: return methods;
103: }
104:
105: private class MethodCollector extends EmptyVisitor {
106:
107: public String super Name;
108: public String[] interfaces;
109: private Set<InheritedMethod> methods;
110:
111: public MethodCollector(Set<InheritedMethod> methods) {
112: this .methods = methods;
113: }
114:
115: public void visit(int version, int access, String name,
116: String signature, String super Name, String[] interfaces) {
117: this .super Name = super Name;
118: this .interfaces = interfaces;
119: }
120:
121: public MethodVisitor visitMethod(int access, String name,
122: String desc, String signature, String[] exceptions) {
123: if ((access & ACC_PRIVATE) == 0
124: && (access & ACC_STATIC) == 0) {
125: methods.add(new InheritedMethod(translator
126: .identifier(name), translator
127: .methodDescriptor(desc), translator
128: .typeNames(exceptions)));
129: }
130: return null;
131: }
132: }
133:
134: private static class InheritedMethod {
135:
136: public final String name;
137: public final String desc;
138: public final String[] exceptions;
139:
140: public InheritedMethod(String name, String desc,
141: String[] exceptions) {
142: this .name = name;
143: this .desc = desc;
144: this .exceptions = exceptions;
145: }
146:
147: public int hashCode() {
148: return name.hashCode();
149: }
150:
151: public boolean equals(Object obj) {
152: if (obj instanceof InheritedMethod) {
153: InheritedMethod method = (InheritedMethod) obj;
154: return name.equals(method.name)
155: && desc.equals(method.desc);
156: }
157: return false;
158: }
159: }
160:
161: }
|