Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Populate existing object #431

Closed
GoogleCodeExporter opened this issue Mar 19, 2015 · 20 comments
Closed

Populate existing object #431

GoogleCodeExporter opened this issue Mar 19, 2015 · 20 comments

Comments

@GoogleCodeExporter
Copy link

It would be great is gson supported the population of existing objects. There 
was a post a while back alluding to this behavior, but it doesn't exist now:

http://groups.google.com/group/google-gson/browse_thread/thread/ab97b754c1f3c53a
?pli=1

The rationale is that this would prevent users from having to create 
TypeAdapters or InstanceCreators for every object that requires custom 
construction, particularly since gson doesn't support the notion of a global 
InstanceCreator at the moment.

Original issue reported on code.google.com by pacesysj...@gmail.com on 8 Apr 2012 at 5:12

@GoogleCodeExporter
Copy link
Author

Note: This is an enhancement (didn't see a setting for this).

Original comment by pacesysj...@gmail.com on 8 Apr 2012 at 5:13

@GoogleCodeExporter
Copy link
Author

Original comment by limpbizkit on 11 Apr 2012 at 8:33

  • Added labels: Type-Enhancement
  • Removed labels: Type-Defect

@GoogleCodeExporter
Copy link
Author

It would be nice if it will be supported :)

http://stackoverflow.com/questions/12277765/it-is-possible-to-fill-current-objec
t-with-json-values-from-json

Original comment by KKoce...@gmail.com on 12 Feb 2013 at 9:03

@GoogleCodeExporter
Copy link
Author

what is the plan for this enhancement? is it on the roadmap?

Original comment by dominik.mengelt on 12 Nov 2013 at 1:34

@GoogleCodeExporter
Copy link
Author

I really like to see this enhancement. I am using the library in my Android 
app. I have a ViewPager with existing items, when a page becomes visible, I 
pull additional items remotely and I would like to populate the additional 
fields in the existing items.

Original comment by tasoman...@gmail.com on 26 Nov 2013 at 9:50

@GoogleCodeExporter
Copy link
Author

Any update on this?
Any chance that it will ever be implemented? any body have a nice work around?
I'm starting a new project and can choose to use Jackson vs GSON, and I'm 
deeply interested in the ability to update existing instance rather than always 
creating new instance.
I'm thinking of creating a new object and then merging to the existing one 
using reflexion but I would rather have this handle at the deserialization 
layer.

Original comment by hugues.b...@gmail.com on 13 Jan 2015 at 10:26

@GoogleCodeExporter
Copy link
Author

See Inderjeet Singh's answer in this thread: 
https://groups.google.com/d/msg/google-gson/q5e3VMHzxTo/DOivwaGC2XoJ

I use the InstanceCreator solution and it works very well. It is far from ideal 
as it requires creating a new Gson instance every time, but it works quite well.

Here is my function :

    public static <T> void populate(GsonBuilder builder, JsonObject json, Class<T> type, T into) {
        builder.registerTypeAdapter(type, new InstanceCreator<T>() {
            @Override public T createInstance(Type t) { return into; }
        }).create().fromJson(json, type);
    }

Original comment by timelza...@gmail.com on 15 Jan 2015 at 2:51

@augustbering
Copy link

Something like this seems to work well for me. I might have missed something but so far, so good...

    /**
     * updates @target object from the @json object. Only fields existing in @json are affected
     * @param target
     * @param json
     * @throws Exception
     */
    public static  void update(Object target, JsonObject json) throws Exception {

        Class<? > class1 = target.getClass();

        Set<Entry<String, JsonElement>> entrySet = json.entrySet();
        for (Entry<String, JsonElement> entry : entrySet) {
            String key = entry.getKey();
            Field field = class1.getField(key);
            Type genType = field.getGenericType();

            field.set(target,
                    gson.fromJson(entry.getValue(),genType));
        }

    }

@Xerosigma
Copy link

For the love of source do NOT use the snippet above as is.

But yes - This is a much needed feature. Just came across a very unfortunate use case.

@ExtinctAmoeba
Copy link

Any update on this?

@bennylut
Copy link

Why this issue was closed? is this became a planned feature? is it rejected?

@inder123
Copy link
Collaborator

You can implement this using InstanceCreators.

final Foo existing;
InstanceCreator<Foo> creator = new InstanceCreator<Foo>() {
  public Foo createInstance(Type type) { return existing; }
}

Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, creator).create();
Foo value = gson.fromJson(jsonString, Foo.class);
// value should be same as existing

@Psidium
Copy link
Contributor

Psidium commented Mar 30, 2016

I needed to update a managed JPA object with a JSON from the web service, this is the solution I've found (I needed to use the local instance of appConfig):

AppConfiguration appConfig = AppConfigurationDAO.getInstance().read(Long.parseLong(req.params(":id")));

InstanceCreator<AppConfiguration> creator = new InstanceCreator<AppConfiguration>() {
    private AppConfiguration appConfig;

    public AppConfiguration createInstance(Type type) {
        return appConfig;
    }

    public InstanceCreator<AppConfiguration> withValue(AppConfiguration appConfig) {
        this.appConfig = appConfig;
        return this;
    }

}.withValue(appConfig);

Gson gson = new GsonBuilder().registerTypeAdapter(AppConfiguration.class, creator).create();
appConfig = gson.fromJson(req.body(), AppConfiguration.class);

return AppConfigurationDAO.getInstance().update(appConfig);

I then stated to wonder: can't we have a InstanceUpdater class? It could have a implementation like this:

import com.google.gson.InstanceCreator;
import java.lang.reflect.Type;

public class InstanceUpdater<T> implements InstanceCreator<T> {

    private T object;

    public T createInstance(Type type) {
        return object;
    }

    public InstanceUpdater(T object) {
        this.object = object;
    }

}

Then I can use with something like this:

InstanceCreator<AppConfiguration> creator = new InstanceUpdater<AppConfiguration>(appConfig);

But I'm not sure, I feel there may be a better way of doing this, and it would be amazing to have something inside Gson to manage this for me.

@Robertiano
Copy link

Why this issue was closed? is this became a planned feature? is it rejected?

@inder123
Copy link
Collaborator

@Robertiano At the moment there is a workaround as outlined above with InstanceCreator.
We are still searching for an elegant proposal.

@eyal-rounds
Copy link

Apparently i need this as well, InstanceCreator is a bad option as if i want to make an extendable class static creators will need to be overwritten since there is no inheritance for that.
Typeadapter creates the object, i seriously think that only copying field without object creation should be easy, if not at least can you supply a static method that can copy the fields using reflection ?

@CreamyCookie
Copy link

CreamyCookie commented Sep 22, 2016

TypeAdapter (example code) worked well for populating an existing object. Just return the instance in the read method.

@derwaldgeist
Copy link

Would love to see this, too.

@mbalick
Copy link

mbalick commented Sep 12, 2019

I've been looking for this functionality for years. @inder123 said "We are still searching for an elegant proposal."
What's wrong with something like gson.fromJson(existingObject, json) ? I don't see why it would not cover the same use cases as gson.fromJson(json).

@redmondgiant
Copy link

redmondgiant commented Aug 28, 2020

For posterity, if this is ever addressed:

Take into account nested reuse of existing objects at any level of the deserialization, not just the root object. Then you can see why InstanceCreator doesn't work.

You would need to pass in the containing object (which itself went through the usual process to be obtained), perhaps the InstanceUpdater where it passes along the containing object as context mainly so it can choose to reuse the T hanging off of it and continue on.

I have use cases (multiple) where I have all sorts of state like event handlers hanging off of important levels of a large tree of objects, and I want essentially all the unimportant "leaf fields" overwritten with incoming values but the important object scaffolding itself remains unchanged at all levels.

This is one of those things that is pretty easy to imagine how to implement it inside Gson, but hard to impossible to do from the outside looking in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests