Question

Je suis en train d'écrire une méthode désérialiseur, qui ressemble à ceci:

public <T> T deserialize(Object[] result, String[] fields, Class<T> type);

Donc, fondamentalement, je vais être passé dans un tableau de résultat des données qui sont tous les objets, et un type T de classe que je dois convertir les données dans le tableau aux types dans la même classe, et de créer une nouvelle classe de type T et le retourner. Les champs String[] sont les noms de champs correspondant aux données en résultat Object[]. Les noms de champs correspondent à la classe T.

Le casting devra utiliser la réflexion de la classe donnée pour savoir le type de chaque champ.

par exemple.

result = ["Mike", "London", 28];
fields = ["name", "location", "age" ];

Classe T =

public class GivenClass{

  private String name;
  private String location;
  private Integer age;

  public GivenClass(String name, String location, Integer age){
    this.name = name;
    this.location = location;
    this.age = age;
  }
}
Était-ce utile?

La solution

Class implementation

static class GivenClass {

    private String name;
    private String location;
    private Integer age;

    public GivenClass(String name, String location, Integer age) {
        this.name = name;
        this.location = location;
        this.age = age;
    }

    public GivenClass(Map<String, Object> data) throws Exception {
        for (Field f : GivenClass.class.getDeclaredFields())
            f.set(this, data.get(f.getName()));
    }

    public Map<String, Object> serialize() throws Exception {
        Map<String, Object> fields = new HashMap<String, Object>();
        for (Field f : GivenClass.class.getDeclaredFields()) 
            fields.put(f.getName(), f.get(this));
        return fields;
    }

    @Override
    public String toString() {
        return "age=" + age + ", location=" + location + ", name=" + name;
    }
}

Example:

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

    GivenClass o1 = new GivenClass("Mike", "London", 28);

    Map<String, Object> serialized = o1.serialize();

    GivenClass o2 = new GivenClass(serialized);
    System.out.println(o2.toString());
}

Output:

age=28, location=London, name=Mike

Autres conseils

You need to do the conversion yourself. Reflections doesn't convert (it will only check the type of an object is already correct)

Reflections won't give you the names of method/constructor parameters. (You can get them from the debug byte code but that's a real pain)

The approach I take is to use the convention that the constructor parameters are in the same order as the fields. You will also want to assume the type of constructor parameters and field types match. ;)

I would also use primitives instead of wrappers whenever possible. Use int unless you want null to be a valid option. If this is the case you should think about how you want to represent this. For text I usually use empty strings or blank field for null or NaN depending on the context.

The problem with this, is that in Java it's unable to fetch the parameter names of a constructor.

For this particular example, you'll need a default constructor, with which you could create an empty object.

public GivenClass() {
  super();
}

Then you could use reflection to get the fields of the class, and then set the appropriate value for them.

But I think it would be much easier to annotate your constructor, and then fetch the annotation informations in your deserialize method. In this case you won't need to fetch the fields and create an empty constructor.

Example:

You need to create a annotation like this:

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property
{
    String value();
}

And then you can use it in your constructor like this:

public GivenClass(@Property("name") String name, @Property("location") String location, @Property("age") Integer age) {
  // ...
}

As Peter Lawrey says, casting does not convert a string into an integer.

If your bean follows the standard bean conventions (ie you have getters & setters), then you can use BeanUtils. BeanUtils does some standard conversions, and you can add more by adding a Convertor.

See the following example:

import org.apache.commons.beanutils.BeanUtils;

public class BeanUtilsTest {
    public static class Obj {
        private int number;
        private String string;

        public void setNumber(int number) {
            this.number = number;
        }
        public void setString(String string) {
            this.string = string;
        }

        public String toString() {
            return "number=" + number + " string=" + string;
        }
    }

    public static void main(String args[]) throws Exception {
        String[] values = new String[] { "1", "two" };
        String[] properties = new String[] { "number", "string" };

        Obj obj = new Obj();

        for (int i = 0; i < properties.length; i++) {
            BeanUtils.setProperty(obj, properties[i], values[i]);
        }

        System.out.println("obj=" + obj);
    }
}

This produces as output:

obj=number=1 string=two

Note that the above example has only setters, but still works.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top