/* * Copyright 2016, Stuart Douglas, and individual contributors as indicated * by the @authors tag. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fakereplace.data; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javassist.bytecode.ClassFile; import javassist.bytecode.Descriptor; import javassist.bytecode.FieldInfo; import javassist.bytecode.MethodInfo; import org.fakereplace.core.Constants; import org.fakereplace.util.DescriptorUtils; /** * This class holds everything there is to know about a class that has been seen * by the transformer. This stores the information about the original class, not * about any modifications * * @author stuart */ public class BaseClassData { private final String className; private final String internalName; private final Set<MethodData> methods; private final List<FieldData> fields; private final ClassLoader loader; private final String superClassName; private final boolean replaceable; public BaseClassData(ClassFile file, ClassLoader loader, boolean replaceable) { className = file.getName(); this.replaceable = replaceable; internalName = Descriptor.toJvmName(file.getName()); this.loader = loader; superClassName = file.getSuperclass(); boolean finalMethod = false; Set<MethodData> meths = new HashSet<MethodData>(); for (Object o : file.getMethods()) { String methodClassName = className; MethodInfo m = (MethodInfo) o; MemberType type = MemberType.NORMAL; if ((m.getDescriptor().equals(Constants.ADDED_METHOD_DESCRIPTOR) && m.getName().equals(Constants.ADDED_METHOD_NAME)) || (m.getDescriptor().equals(Constants.ADDED_STATIC_METHOD_DESCRIPTOR) && m.getName().equals(Constants.ADDED_STATIC_METHOD_NAME)) || (m.getDescriptor().equals(Constants.ADDED_CONSTRUCTOR_DESCRIPTOR))) { type = MemberType.ADDED_SYSTEM; } else if (m.getAttribute(Constants.FINAL_METHOD_ATTRIBUTE) != null) { finalMethod = true; } MethodData md = new MethodData(m.getName(), m.getDescriptor(), methodClassName, type, m.getAccessFlags(), finalMethod); meths.add(md); } this.methods = Collections.unmodifiableSet(meths); List<FieldData> fieldData = new ArrayList<>(); for (Object o : file.getFields()) { FieldInfo m = (FieldInfo) o; MemberType mt = MemberType.NORMAL; fieldData.add(new FieldData(m, mt, className, m.getAccessFlags())); } this.fields = Collections.unmodifiableList(fieldData); } public BaseClassData(Class<?> cls) { className = cls.getName(); internalName = Descriptor.toJvmName(cls.getName()); this.loader = cls.getClassLoader(); replaceable = false; if (cls.getSuperclass() != null) { superClassName = cls.getSuperclass().getName(); } else { superClassName = null; } Set<MethodData> meths = new HashSet<MethodData>(); for (Method m : cls.getDeclaredMethods()) { MemberType type = MemberType.NORMAL; final String descriptor = DescriptorUtils.getDescriptor(m); if ((descriptor.equals(Constants.ADDED_METHOD_DESCRIPTOR) && m.getName().equals(Constants.ADDED_METHOD_NAME)) || (descriptor.equals(Constants.ADDED_STATIC_METHOD_DESCRIPTOR) && m.getName().equals(Constants.ADDED_STATIC_METHOD_NAME))) { type = MemberType.ADDED_SYSTEM; } MethodData md = new MethodData(m.getName(), descriptor, cls.getName(), type, m.getModifiers(), false); meths.add(md); } for (Constructor<?> c : cls.getDeclaredConstructors()) { MemberType type = MemberType.NORMAL; final String descriptor = DescriptorUtils.getDescriptor(c); if (descriptor.equals(Constants.ADDED_CONSTRUCTOR_DESCRIPTOR)) { type = MemberType.ADDED_SYSTEM; } MethodData md = new MethodData("<init>", descriptor, cls.getName(), type, c.getModifiers(), false); meths.add(md); } this.methods = Collections.unmodifiableSet(meths); List<FieldData> fieldData = new ArrayList<FieldData>(); for (Field m : cls.getDeclaredFields()) { fieldData.add(new FieldData(m)); } this.fields = Collections.unmodifiableList(fieldData); } public String getSuperClassName() { return superClassName; } public ClassLoader getLoader() { return loader; } public String getClassName() { return className; } public String getInternalName() { return internalName; } public Collection<MethodData> getMethods() { return methods; } public Collection<FieldData> getFields() { return fields; } public boolean isReplaceable() { return replaceable; } public FieldData getField(String fieldName) { for(FieldData field : fields) { if(field.getName().equals(fieldName)) { return field; } } return null; } public MethodData getMethodOrConstructor(String methodName, String methodDesc) { for(MethodData method : methods) { if(method.getMethodName().equals(methodName) && method.getDescriptor().equals(methodDesc)) { return method; } } return null; } }