Pregunta

I have a class with custom object types nested. When I create an instance, I would like to have instance created with default values and also for the nested objects. I am checking if there is any utility class available in Apache Bean Utils but no luck yet. Is there any easy way to do this? If not, I have to write a recursion function to do this. E.g.

A{
 int x;
 B b;
 C c;    
}

B{
 boolean y;
 D d;     
}

D{
 String z;
}

Object a = A.class.newInstance();

The above should give me an object like below, where a,b,c,d are populated with default values (for primitives only)

 a 
  |--> x (=0)
  |
  |--> b
  |
  |--> c
       |--> y (=false)
       |
       |--> d
            |--> x (=null)

Without changing the structure of the actual classes, I would like to create an instance with empty object deeply created. Any thoughts highly appreciated!

¿Fue útil?

Solución

This will do what you want with some caveats:

  • It assumes there is a default constructor.
  • It skips primitives.
  • It skips already initialised objects.
  • It will only initialize the packages specified (startsWith match) to avoid initializing other things like HashMaps etc that get very messy.
  • It has only been tested with simple objects.
  • You might not be able to access the fields if your have a security manager policy set.
  • If there is any kind of recursive loop such as obj_A has a obj_B has a obj_A then it will fail with a stack overflow.
  • It won't access and set values from superclasses (but could be made to).

I would ask if this is the best solution though as it would be prone to failure if things aren't quite as expected deep in the objects.

Initializer.java

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

import org.example.something.A;

public class Initilizer {

    public static void initialize(Object object, Set<String> packages)
            throws IllegalArgumentException,
            IllegalAccessException {
        Field[] fields = object.getClass().getDeclaredFields();

        for (Field field : fields) {
            String fieldName = field.getName();
            Class<?> fieldClass = field.getType();

            // skip primitives
            if (fieldClass.isPrimitive()) {
                System.out.println("Skipping primitive: " + fieldName);
                continue;
            }

            // skip if not in packages
            boolean inPackage = false;
            for (String pack : packages) {
                if (fieldClass.getPackage().getName().startsWith(pack)) {
                    inPackage = true;
                }
            }
            if (!inPackage) {
                System.out.println("Skipping package: "
                        + fieldClass.getPackage().getName());
                continue;
            }

            // allow access to private fields
            boolean isAccessible = field.isAccessible();
            field.setAccessible(true);

            Object fieldValue = field.get(object);
            if (fieldValue == null) {
                System.out.println("Initializing: " + fieldName);
                try {
                    field.set(object, fieldClass.newInstance());
                } catch (IllegalArgumentException | IllegalAccessException
                        | InstantiationException e) {
                    System.err.println("Could not initialize "
                            + fieldClass.getSimpleName());
                }
            } else {
                System.out
                        .println("Field is already initialized: " + fieldName);
            }

            fieldValue = field.get(object);

            // reset accessible
            field.setAccessible(isAccessible);

            // recursive call for sub-objects
            initialize(fieldValue, packages);
        }

    }

    public static void main(String[] args) throws Exception {

        A a = new A();

        // Packages to initialize
        Set<String> packages = new HashSet<>();
        packages.add("com.example");
        packages.add("org.example");

        initialize(a, packages);
    }
}

A.java

package org.example.something;

import com.example.other.B;

public class A {

    private int x;

    private B b;

    private B be = new B();

    private C c;

}

B.java

package com.example.other;

public class B {

    private boolean y;

    private D d;

}

C.java

package org.example.something;
import java.util.HashMap;

public class C {

    private HashMap doNotInit;

}

D.java

package com.example.other;

public class D {

    private String s;

}

Output

Skipping primitive: x
Initializing: b
Skipping primitive: y
Initializing: d
Skipping package: java.lang
Field is already initialized: be
Skipping primitive: y
Initializing: d
Skipping package: java.lang
Initializing: c
Skipping package: java.util
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top