adding an object using a custom typeadapter, jsonwriter in gson

前端 未结 2 2074
攒了一身酷
攒了一身酷 2020-12-09 05:33

gson is a great library - it works well. Sometimes I have custom requirements, and can make and register TypeAdapters and TypeAdaptorFactories - and that works well too. <

相关标签:
2条回答
  • 2020-12-09 05:56

    actually that seemed to work - getting the adapter for object - using the typeadaptorfactory to discover a "json" method on an object, and having that store away the adaptor object. Seems astonishingly complex for what is such an obvious use case?

    eg:

    public static @Nullable
    TypeAdapter<ImmutableStack<?>> json(final Gson gson)
    {
        final TypeAdapter<Object> adaptor = gson.getAdapter(Object.class);
        return new TypeAdapter<ImmutableStack<?>>()
        {
            @Override
            public ImmutableStack<?> read(@Nullable final JsonReader in) throws IOException
            {
                throw ProgramError.notImplementedYet();
            }
            @Override
            public void write(final JsonWriter out, final ImmutableStack<?> value) throws IOException
            {
                out.beginArray();
                for (final Object inner : value)
                    adaptor.write(out, inner);
                out.endArray();
            }
        };
    }
    

    does anyone know a better way to do it?

    0 讨论(0)
  • 2020-12-09 06:06

    In this case its better to use a JsonSerializer as opposed to a TypeAdapter, for the simple reason that serializers have access to their serialization context:

    public class PairSerializer implements JsonSerializer<Pair> {
    
        public PairSerializer() {
            super();
        }
    
        @Override
        public JsonElement serialize(final Pair value, final Type type,
                final JsonSerializationContext context) {
            final JsonObject jsonObj = new JsonObject();
            jsonObj.add("first", context.serialize(value.getFirst()));
            jsonObj.add("second", context.serialize(value.getSecond()));
    
            return jsonObj;
        }
    }
    

    The above sample code illustrates how to delegate serialization of target objects back to the main marshaller. The main advantage of this (apart from avoiding complicated workarounds) is that you can still take advantage of other type adaptors and custom serializers that might have been registered in the main context. Note that registration of serializers and adapters use the exact same code:

    // With adapter
    final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class,
            new PairAdapter()).create();
    
    // With serializer
    final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class,
            new PairSerializer()).create();
    

    If you find that you need to stick with an adapter, then you can use an embedded Gson proxy to serialize the Pair properties for you, with the disadvantage that you lose access to custom registrations that you made on the parent Gson proxy:

    public class PairAdapter extends TypeAdapter<Pair> {
        final Gson embedded = new Gson();
    
        public PairAdapter() {
            super();
        }
    
        @Override
        public void write(final JsonWriter out, final Pair value)
                throws IOException {
            out.beginObject();
    
            out.name("first");
            embedded.toJson(embedded.toJsonTree(value.getFirst()), out);
    
            out.name("second");
            embedded.toJson(embedded.toJsonTree(value.getSecond()), out);
    
            out.endObject();
        }
    
        @Override
        public Pair read(JsonReader in) throws IOException {
            throw new UnsupportedOperationException();
        }
    }
    
    0 讨论(0)
提交回复
热议问题