Search in sources :

Example 1 with FieldData

use of org.fakereplace.data.FieldData in project fakereplace by fakereplace.

the class FieldReplacementTransformer method transform.

@Override
public boolean transform(ClassLoader loader, String className, Class<?> oldClass, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    if (oldClass == null || className == null) {
        return false;
    }
    BaseClassData data = ClassDataStore.instance().getBaseClassData(loader, Descriptor.toJvmName(file.getName()));
    Set<FieldData> fields = new LinkedHashSet<>();
    fields.addAll(data.getFields());
    ListIterator<?> it = file.getFields().listIterator();
    final Set<FieldData> toRemove = new HashSet<>();
    final Set<FieldProxyInfo> toAdd = new HashSet<>();
    while (it.hasNext()) {
        FieldInfo m = (FieldInfo) it.next();
        FieldData md = null;
        for (FieldData i : fields) {
            if (i.getName().equals(m.getName()) && i.getType().equals(m.getDescriptor()) && i.getAccessFlags() == m.getAccessFlags()) {
                try {
                    Field field = i.getField(oldClass);
                    AnnotationDataStore.recordFieldAnnotations(field, (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag));
                    // now revert the annotations:
                    m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), field));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                md = i;
                break;
            }
        }
        // This is a newly added field.
        if (md == null) {
            int fieldNo = addField(loader, m, toAdd, oldClass);
            Transformer.getManipulator().rewriteInstanceFieldAccess(fieldNo, m.getName(), m.getDescriptor(), file.getName(), loader);
            it.remove();
        } else {
            fields.remove(md);
        }
    }
    // TODO: rewrite classes that access them to throw a NoSuchFieldError
    for (FieldData md : fields) {
        if (md.getMemberType() == MemberType.NORMAL) {
            FieldInfo old = new FieldInfo(file.getConstPool(), md.getName(), md.getType());
            old.setAccessFlags(md.getAccessFlags());
            toRemove.add(md);
        }
    }
    // clear all the fields and re-add them in the correct order
    // turns out order is important
    file.getFields().clear();
    for (FieldData md : data.getFields()) {
        if (md.getMemberType() == MemberType.NORMAL) {
            try {
                Field field = md.getField(oldClass);
                FieldInfo old = new FieldInfo(file.getConstPool(), md.getName(), md.getType());
                old.setAccessFlags(md.getAccessFlags());
                file.addField(old);
                old.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), field));
            } catch (DuplicateMemberException | SecurityException | NoSuchFieldException e) {
                // this should not happen
                throw new RuntimeException(e);
            }
        }
    }
    ClassDataStore.instance().modifyCurrentData(loader, file.getName(), (builder) -> {
        for (FieldProxyInfo field : toAdd) {
            builder.addFakeField(field.fieldData, field.proxyName, field.modifiers);
        }
        for (FieldData field : toRemove) {
            builder.removeField(field);
        }
    });
    return true;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) FieldData(org.fakereplace.data.FieldData) Field(java.lang.reflect.Field) BaseClassData(org.fakereplace.data.BaseClassData) FieldInfo(javassist.bytecode.FieldInfo) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 2 with FieldData

use of org.fakereplace.data.FieldData in project fakereplace by fakereplace.

the class FieldReflection method getDeclaredFields.

public static Field[] getDeclaredFields(Class<?> clazz) {
    if (!ClassDataStore.instance().isClassReplaced(clazz)) {
        return clazz.getDeclaredFields();
    }
    try {
        ClassData cd = ClassDataStore.instance().getModifiedClassData(clazz.getClassLoader(), Descriptor.toJvmName(clazz.getName()));
        Field[] meth = clazz.getDeclaredFields();
        Collection<FieldData> fieldData = cd.getFields();
        List<Field> visible = new ArrayList<>(meth.length);
        for (int i = 0; i < meth.length; ++i) {
            for (FieldData f : fieldData) {
                if (f.getAccessFlags() == meth[i].getModifiers() && f.getName().equals(meth[i].getName())) {
                    if (f.getMemberType() == MemberType.NORMAL) {
                        visible.add(meth[i]);
                        break;
                    }
                }
            }
        }
        for (FieldData i : cd.getFields()) {
            if (i.getMemberType() == MemberType.FAKE) {
                Class<?> c = clazz.getClassLoader().loadClass(i.getClassName());
                visible.add(i.getField(c));
            }
        }
        Field[] ret = new Field[visible.size()];
        for (int i = 0; i < visible.size(); ++i) {
            ret[i] = visible.get(i);
        }
        return ret;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : FieldData(org.fakereplace.data.FieldData) Field(java.lang.reflect.Field) ClassData(org.fakereplace.data.ClassData) ArrayList(java.util.ArrayList)

Example 3 with FieldData

use of org.fakereplace.data.FieldData in project fakereplace by fakereplace.

the class FieldReflection method getFields.

public static Field[] getFields(Class<?> clazz) {
    if (!ClassDataStore.instance().isClassReplaced(clazz)) {
        return clazz.getFields();
    }
    try {
        ClassData cd = ClassDataStore.instance().getModifiedClassData(clazz.getClassLoader(), Descriptor.toJvmName(clazz.getName()));
        if (cd == null) {
            return clazz.getDeclaredFields();
        }
        Field[] meth = clazz.getFields();
        Collection<FieldData> fieldData = cd.getFields();
        List<Field> visible = new ArrayList<>(meth.length);
        for (int i = 0; i < meth.length; ++i) {
            for (FieldData f : fieldData) {
                if (f.getAccessFlags() == meth[i].getModifiers() && f.getName().equals(meth[i].getName())) {
                    if (f.getMemberType() == MemberType.NORMAL) {
                        visible.add(meth[i]);
                        break;
                    }
                }
            }
        }
        ClassData cta = cd;
        while (cta != null) {
            for (FieldData i : cta.getFields()) {
                if (i.getMemberType() == MemberType.FAKE && AccessFlag.isPublic(i.getAccessFlags())) {
                    Class<?> c = clazz.getClassLoader().loadClass(i.getClassName());
                    visible.add(i.getField(c));
                }
            }
            cta = cta.getSuperClassInformation();
        }
        Field[] ret = new Field[visible.size()];
        for (int i = 0; i < visible.size(); ++i) {
            ret[i] = visible.get(i);
        }
        return ret;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : FieldData(org.fakereplace.data.FieldData) Field(java.lang.reflect.Field) ClassData(org.fakereplace.data.ClassData) ArrayList(java.util.ArrayList)

Example 4 with FieldData

use of org.fakereplace.data.FieldData in project fakereplace by fakereplace.

the class FieldReflection method getField.

public static Field getField(Class<?> clazz, String name) throws NoSuchFieldException {
    if (!ClassDataStore.instance().isClassReplaced(clazz)) {
        return clazz.getField(name);
    }
    ClassData cd = ClassDataStore.instance().getModifiedClassData(clazz.getClassLoader(), Descriptor.toJvmName(clazz.getName()));
    if (cd == null) {
        return clazz.getField(name);
    }
    FieldData fd = cd.getField(name);
    if (fd == null) {
        return clazz.getField(name);
    }
    if (!AccessFlag.isPublic(fd.getAccessFlags())) {
        throw new NoSuchFieldException(clazz.getName() + "." + name);
    }
    switch(fd.getMemberType()) {
        case NORMAL:
            return clazz.getField(name);
        case FAKE:
            try {
                Class<?> c = clazz.getClassLoader().loadClass(fd.getClassName());
                return c.getField(name);
            } catch (NoSuchFieldException e) {
                throw e;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    }
    throw new NoSuchFieldException();
}
Also used : FieldData(org.fakereplace.data.FieldData) ClassData(org.fakereplace.data.ClassData)

Example 5 with FieldData

use of org.fakereplace.data.FieldData in project fakereplace by fakereplace.

the class FieldReflection method getDeclaredField.

public static Field getDeclaredField(Class<?> clazz, String name) throws NoSuchFieldException {
    if (!ClassDataStore.instance().isClassReplaced(clazz)) {
        return clazz.getDeclaredField(name);
    }
    ClassData cd = ClassDataStore.instance().getModifiedClassData(clazz.getClassLoader(), Descriptor.toJvmName(clazz.getName()));
    if (cd == null) {
        return clazz.getDeclaredField(name);
    }
    FieldData fd = cd.getField(name);
    if (fd == null) {
        return clazz.getDeclaredField(name);
    }
    switch(fd.getMemberType()) {
        case NORMAL:
            return clazz.getDeclaredField(name);
        case FAKE:
            try {
                Class<?> c = clazz.getClassLoader().loadClass(fd.getClassName());
                return c.getDeclaredField(name);
            } catch (NoSuchFieldException e) {
                throw e;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    }
    throw new NoSuchFieldException();
}
Also used : FieldData(org.fakereplace.data.FieldData) ClassData(org.fakereplace.data.ClassData)

Aggregations

FieldData (org.fakereplace.data.FieldData)6 ClassData (org.fakereplace.data.ClassData)4 Field (java.lang.reflect.Field)3 ArrayList (java.util.ArrayList)2 BaseClassData (org.fakereplace.data.BaseClassData)2 IOException (java.io.IOException)1 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 Set (java.util.Set)1 Bytecode (javassist.bytecode.Bytecode)1 CodeIterator (javassist.bytecode.CodeIterator)1 ConstPool (javassist.bytecode.ConstPool)1 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)1 FieldInfo (javassist.bytecode.FieldInfo)1 MethodInfo (javassist.bytecode.MethodInfo)1