私は(そのネストされたオブジェクトと一緒に)オブジェクトのすべての文字列プロパティを変換したいと私は、リフレクションAPIでそれを達成するために、次の再帰的な方法を使用しています:
public static void reflect(Object obj) {
if (obj == null) {
return;
}
Class klazz = obj.getClass();
if (klazz.isPrimitive()
|| obj instanceof Integer
|| obj instanceof Double
|| obj instanceof Boolean)
return;
else {
try {
for (Field field : klazz.getDeclaredFields()) {
field.setAccessible(true);
Object f = field.get(obj);
if(f instanceof String) {
f = transform(f);
field.set(obj, f);
}
else {
reflect(f);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
private static Object transform(Object f) {
f = f + "blabla";
return f;
}
@Data
@Builder
public class PrintObject {
private String field1;
private String field2;
private String field3;
private NestedObject field4;
}
@Data
@Builder
public class NestedObject {
private String field1;
private String field2;
private Integer field3;
}
NestedObject nestedObject = NestedObject
.builder()
.field1("test")
.field2("test2")
.field3(1)
.build();
PrintObject printObject = PrintObject
.builder()
.field1("test")
.field2("Test")
.field3("test")
.field4(nestedObject)
.build();
Utils.reflect(printObject);
この時点まで、すべてはうまく動作しますし、私はこれを実行した場合、すべての文字列値は最後に「blabla」が付加されています。PrintObjectは、リスト、またはマップのような他のデータ構造を持っている場合、問題が来ます。例えばPrintObjectクラス内の別のフィールドが存在する場合:
private List<String> field5;
その後、このコードの実行はStackOverflowErrorがをスローしていました。
List<String> list = new ArrayList<>();
list.add("test");
NestedObject nestedObject = NestedObject
.builder()
.field1("test")
.field2("test2")
.field3(1)
.build();
PrintObject printObject = PrintObject
.builder()
.field1("test")
.field2("Test")
.field3("test")
.field4(nestedObject)
.field5(list)
.build();
Utils.reflect(printObject);
だけでなく、これらの構造で、この作業を行う方法上の任意のアイデア?前もって感謝します。
フィールド5には、例えば次のようになります。
Map<String,String>
あるいは
List<List<String>>
ArrayList
含まれているlong
serialVersionUID
シリアル化を支援するためのフィールドを。あなたが値を取得する場合には、箱入りを返しますLong
。呼び出しgetDeclaredFields
にLong
戻るフィールドを含む配列Long.MIN_VALUE
ですLong
。無限ループがどこから来ているのです。
それを解決するために、私はのための特殊なケースの取り扱いを追加しLong
、あなたがのために行うようにInteger
。また、のような他のすべての箱入りのプリミティブを検討すべきであるFloat
としByte
。
コレクションは互いにリンクを指す構造のいずれかによって裏付けされるLinkedList
または配列によって。リンクされた構造のためのコードでは、それらを横断します。サポートアレイにあなたがそれらの上に配列し、反復されたフィールドを識別するために必要な収集支持しました。
フィールドのタイプとを用いて得ることField.getType。配列はで識別することができClass.isArray。さまざまな種類の配列が異なる種類を持って、彼らは、Javaのジェネリックのような非具体化ではありません。非プリミティブ値の配列をにキャストすることができObject[]
、この場合に有用であるが、それはあるタイプセーフではありません。配列内のオブジェクトの種類を取得するにはClass.getComponentTypeは使用することができます。
次のようなものは、配列のエントリに再帰するのに必要とされるであろう。
final Class<?> fieldType = field.getType();
if (fieldType.isArray() && !fieldType.getComponentType().isPrimitive()) {
Object[] fs = (Object[]) f;
for (Object fi : fs) {
reflect(fi);
}
}
他の問題がさらに発生する可能性があり循環参照ですStackOverflowException
。リストは、それ自体にメンバーとして追加された場合には、無限に再帰でしょう。以前に訪問したオブジェクトを追跡し、二度、それらを訪問していないことが必要です。理想的には、これは使用することになりIdentityHashMap
、あなたがオブジェクトのインスタンスではない彼らの平等を気として。