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;
}
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);
}
}
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);
}
}
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();
}
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();
}
Aggregations