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 net.sf.retrotranslator.runtime.impl.*;
036:
037: /**
038: * @author Taras Puchko
039: */
040: class SmartReplacementVisitor extends EmptyVisitor {
041:
042: private final ReplacementLocator locator;
043: private final NameTranslator translator;
044: private boolean enabled;
045: private Set<String> constructorDescriptors = new HashSet<String>();
046: private Map<MemberKey, MemberReplacement> fieldReplacements;
047: private Map<MemberKey, MemberReplacement> methodReplacements;
048: private Map<String, MemberReplacement> converterReplacements;
049: private Map<String, ConstructorReplacement> constructorReplacements;
050:
051: public SmartReplacementVisitor(ReplacementLocator locator) {
052: this .locator = locator;
053: this .translator = locator.getTranslator();
054: }
055:
056: public void addInheritedMembers(ClassReplacement replacement) {
057: if (enabled) {
058: cleanConstructorReplacements();
059: cleanConverterReplacements();
060: copyIfAbsent(fieldReplacements, replacement
061: .getFieldReplacements());
062: copyIfAbsent(methodReplacements, replacement
063: .getMethodReplacements());
064: copyIfAbsent(converterReplacements, replacement
065: .getConverterReplacements());
066: copyIfAbsent(constructorReplacements, replacement
067: .getConstructorReplacements());
068: }
069: }
070:
071: private void cleanConstructorReplacements() {
072: Iterator<ConstructorReplacement> iterator = constructorReplacements
073: .values().iterator();
074: while (iterator.hasNext()) {
075: ConstructorReplacement replacement = iterator.next();
076: if (!constructorDescriptors.contains(replacement
077: .getConstructorDesc())) {
078: iterator.remove();
079: }
080: }
081: }
082:
083: private void cleanConverterReplacements() {
084: Iterator<MemberReplacement> iterator = converterReplacements
085: .values().iterator();
086: while (iterator.hasNext()) {
087: MemberReplacement replacement = iterator.next();
088: if (!constructorDescriptors.contains(ClassReplacement
089: .getConstructorDesc(replacement))) {
090: iterator.remove();
091: }
092: }
093: }
094:
095: public void visit(int version, int access, String name,
096: String signature, String super Name, String[] interfaces) {
097: if ((access & Opcodes.ACC_INTERFACE) != 0 || super Name == null) {
098: return;
099: }
100: super Name = locator.getUniqueTypeName(super Name);
101: ClassReplacement replacement = locator
102: .getReplacement(super Name);
103: if (replacement == null) {
104: return;
105: }
106: enabled = true;
107: fieldReplacements = wrap(replacement.getFieldReplacements());
108: methodReplacements = wrap(replacement.getMethodReplacements());
109: converterReplacements = wrap(replacement
110: .getConverterReplacements());
111: constructorReplacements = wrap(replacement
112: .getConstructorReplacements());
113: }
114:
115: public FieldVisitor visitField(int access, String name,
116: String desc, String signature, Object value) {
117: if (enabled && (access & Opcodes.ACC_STATIC) != 0) {
118: MemberKey key = new MemberKey(true, translator
119: .identifier(name), translator.typeDescriptor(desc));
120: fieldReplacements.remove(key);
121: }
122: return null;
123: }
124:
125: public MethodVisitor visitMethod(int access, String name,
126: String desc, String signature, String[] exceptions) {
127: if (enabled) {
128: String descriptor = translator.methodDescriptor(desc);
129: if (name.equals(RuntimeTools.CONSTRUCTOR_NAME)) {
130: constructorDescriptors.add(descriptor);
131: converterReplacements.remove(descriptor);
132: constructorReplacements.remove(descriptor);
133: } else {
134: boolean statical = (access & Opcodes.ACC_STATIC) != 0;
135: methodReplacements.remove(new MemberKey(statical,
136: translator.identifier(name), descriptor));
137: }
138: }
139: return null;
140: }
141:
142: private <K, V> void copyIfAbsent(Map<K, V> source,
143: Map<K, V> destination) {
144: for (Map.Entry<K, V> entry : source.entrySet()) {
145: if (!destination.containsKey(entry.getKey())) {
146: destination.put(entry.getKey(), entry.getValue());
147: }
148: }
149: }
150:
151: private static <K, V> Map<K, V> wrap(Map<K, V> map) {
152: return new HashMap<K, V>(map);
153: }
154:
155: }
|