Reputation: 1564
I have some code that relies on reflection (working with a third-party libarary) to get the fields of a class. Many of these classes use a mix of the same fields, some nearly identical but with a few differences.
This has led to a ton of code duplication, but I'm not sure of a nice pattern around it due to the reliance reflection.
According to the documentation:
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
This rules out an Abstract class or any inheritence-related solutions.
Here's a code example (MyField
represents a third-party library object, and myData
is a public member of MyField
):
ClassA.java
public class ClassA {
private final Field[] myFields;
private final MyField a = new MyField(1);
private final MyField b = new MyField(2);
private final MyField c = new MyField(3);
public ClassA() {
myFields = this.getClass().getDeclaredFields();
}
public void doStuff(Field[] myFields) {
// As an example, this clears out the field values.
// There are several of these methods that use or manipulate the fields
for (Field f : myFields) {
if (f.getType() == MyField.class
|| f.getType().getSuperclass() == MyField.class) {
try {
f.setAccessible(true);
((MyField) f.get(this)).myData.reset();
}
catch (IllegalArgumentException | IllegalAccessException e) {
continue;
}
}
}
}
public Field[] getFields() {
return Arrays.copyOf(myFields, myFields.length);
{
}
ClassB.java
public class ClassB {
private final Field[] myFields;
private final MyField a = new MyField(1);
private final MyField c = new MyField(3);
private final MyField d = new MyField(4);
public ClassB() {
myFields = this.getClass().getDeclaredFields();
}
public void doStuff(Field[] myFields) {
// Same as above
}
public Field[] getFields() {
return Arrays.copyOf(myFields, myFields.length);
{
}
Note that ClassA
and ClassB
share fields a
and c
and methods getFields()
and doStuff()
.
Is there any way to shore up some of this duplication without affecting the reflection?
Upvotes: 0
Views: 478
Reputation: 51034
Why do the fields need to be stored in an array within the class? It seems that obj.getFields()
is always equivalent to obj.getClass().getDeclaredFields()
. Note that getDeclaredFields
returns a new array each time anyway, so calling it once and then making a defensive copy on your own getter is superfluous.
If you prefer the readability of obj.getFields()
then you could make this a default interface method, and inherit it on each class from the interface without having to change the class hierarchy:
public interface FieldGetter {
default Field[] getFields() {
return this.getClass().getDeclaredFields();
}
}
Example:
> class A implements FieldGetter { int x; String y; }
> new A().getFields()
Field[2] { int A.x, java.lang.String A.y }
It's not clear whether your doStuff
method does the same thing on each class; if so, you can make that a default interface method, too.
By the way, the fact that getDeclaredFields
doesn't return superclass fields isn't a barrier to having a class hierarchy, because you can call it on the superclasses too; see this other question.
Upvotes: 1