Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid overwriting of non-null values with null values?

I'm using spring MVC for receiving a JSON from client and automatically create an object from it. The problem is that the client doesn't send to server all the fields that are in the entity, but some fields are null and overwrite existing values calling userDao.persist(user). For example, i have this entity:

@Entity
public class User {

    @Id @GeneratedValue
    private int id;

    private String username;
    private String password;
    private String email;

But the user never send me the password, so the object built from JSON has "password" field empty. I don't want the password field to be overwritten by a null value. There's a way to say to hibernate "if you find a null value ignore it and don't overwrite the value that is saved in database?". I can't believe that there isn't a easy solution to this apparently simple problem.

like image 434
Fabio Avatar asked Sep 19 '11 15:09

Fabio


2 Answers

I think the source of your problem is that the object you're getting back from your JSON parsing never had the actual values in it. It is a bean that has only the values set that are in your JSON.

You need to load your entity from the DB and then set the non-null fields from your JSON onto the loaded entity. That way only fields that are supplied in the JSON will be set.

I recommend an adapter of some sort to "merge" (not JPA merge) the DB version and the JSON version before saving the DB version.

Adding a @NotNull constraint and Bean Validation will make sure the values are not null when attempting to save. Unfortunately they won't help you get the values into the entity to save.

like image 76
James DW Avatar answered Oct 24 '22 05:10

James DW


I have the same issue. I solved it in this way.

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import java.lang.reflect.Field;
import java.util.Hashtable;



public class Updater {

private final static Logger log = LogManager.getLogger(Updater.class);

public static <E> E updater(E oldEntity, E newEntity) {

    Field[] newEntityFields = newEntity.getClass().getDeclaredFields();
    Hashtable newHT = fieldsToHT(newEntityFields, newEntity);

    Class oldEntityClass = oldEntity.getClass();
    Field[] oldEntityFields = oldEntityClass.getDeclaredFields();

    for (Field field : oldEntityFields){
        field.setAccessible(true);
        Object o = newHT.get(field.getName());
        if (o != null){
            try {
                Field f = oldEntityClass.getDeclaredField(field.getName());
                f.setAccessible(true);
                log.info("setting " + f.getName());
                f.set(oldEntity, o);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }

        }

    return oldEntity;
    }



private static Hashtable<String, Object> fieldsToHT(Field[] fields, Object obj){
    Hashtable<String,Object> hashtable = new Hashtable<>();
    for (Field field: fields){
        field.setAccessible(true);
        try {
            Object retrievedObject = field.get(obj);
            if (retrievedObject != null){
                log.info("scanning " + field.getName());
                hashtable.put(field.getName(), field.get(obj));
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    return hashtable;
}
}

It is clearly a workaround but it seems to work smoothly... in the next days I think I'll write the recursive part.

like image 36
Paolinux Avatar answered Oct 24 '22 05:10

Paolinux