首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Gson:是否有更有效的方法来对详细的Json对象进行自定义(反)序列化

Gson:是否有更有效的方法来对详细的Json对象进行自定义(反)序列化
EN

Stack Overflow用户
提问于 2018-03-23 19:01:03
回答 1查看 777关注 0票数 0

我正在处理一些我称之为详细的json对象:

代码语言:javascript
复制
{
  "user": {
    "name": "username",
    "email": "blah@blah.com",
    "time_zone": "America/New_York"
  }
}

但是,我更愿意用java POJO来处理它们,例如:

代码语言:javascript
复制
class UserDetails {
    String name;
    String email;
    String timeZone;
    ...
}

请注意,在生成代码时,我无法控制POJO。

我对(反)序列化的两个要求是

  • timeZone字段映射到JSON中的time_zone
  • 忽略外部user

所以我有一些客户(反)序列化程序:

代码语言:javascript
复制
    class UserDeserializer implements JsonDeserializer<UserDetails> {
        @Override
        public UserDetails deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
            throws JsonParseException {
            JsonElement content = je.getAsJsonObject().get("user");
            UserDetails userDetails = new GsonBuilder()
                .setFieldNamingStrategy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                .create()
                .fromJson(content, UserDetails.class);
            return userDetails;
        }
    }

    class UserSerializer implements JsonSerializer<UserDetails> {
        @Override
        public JsonElement serialize(UserDetails userDetails, Type typeOfSrc,
                                     JsonSerializationContext context) {
            JsonObject obj = new JsonObject();
            JsonElement je = new GsonBuilder()
                    .setFieldNamingStrategy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                    .create().toJsonTree(userDetails);
            obj.add("user", je);
            return obj;

        }
    }

我觉得在(反)序列化程序逻辑中创建新的Gson对象并不理想/有效,只需要添加和删除最外层的user键。

编辑:实际上,.setFieldNamingStrategy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)在反序列化方面确实工作得很好。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-23 22:21:37

总的来说,我并不认为这是一个好主意,而且您可能最好有一个Wrapper<T>,用于所有“最高级”的目的(如果您不希望内部对象被认为是“冗长的”)。但你说得对

我觉得在(反)序列化逻辑中创建新的Gson对象并不理想/有效,只是为了添加和删除最外层的用户键。

所以:

  • 创建Gson是一个相对昂贵的操作。
  • 这只会创建不必要的对象并命中堆。
  • Gson可能是以一种特殊的方式配置的,您可能希望在任何地方共享相同的Gson配置。
  • JsonSerializerJsonDeserializer操作于JSON树(JsonElement及其子类),因此它在序列化/反序列化之前/之后创建中间内存树表示。

您可能会考虑一个更快的解决方案,这是不需要这些项目的。

代码语言:javascript
复制
final class VerboseTypeAdapterFactory
        implements TypeAdapterFactory {

    private final Map<Class<?>, String> mappings;

    private VerboseTypeAdapterFactory(final Map<Class<?>, String> mappings) {
        this.mappings = mappings;
    }

    static TypeAdapterFactory get(final Map<Class<?>, String> mappings) {
        // Create a defensive copy to make sure the map is not modified from outside
        final Map<Class<?>, String> mappingsCopy = mappings
                .entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        return new VerboseTypeAdapterFactory(mappingsCopy);
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final Class<? super T> rawType = typeToken.getRawType();
        // Not something we can handle?
        if ( !mappings.containsKey(rawType) ) {
            // Then let Gson do its job elsewhere
            return null;
        }
        // Getting a property name we want to use for a particular class
        final String propertyName = mappings.get(rawType);
        // And getting the original type adapter for this class (effectively ReflectiveTypeAdapterFactory.Adapter)
        final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
        return VerboseTypeAdapter.get(propertyName, delegateTypeAdapter);
    }

    private static final class VerboseTypeAdapter<T>
            extends TypeAdapter<T> {

        private final String propertyName;
        private final TypeAdapter<T> delegateTypeAdapter;

        private VerboseTypeAdapter(final String propertyName, final TypeAdapter<T> delegateTypeAdapter) {
            this.propertyName = propertyName;
            this.delegateTypeAdapter = delegateTypeAdapter;
        }

        private static <T> TypeAdapter<T> get(final String propertyName, final TypeAdapter<T> delegateTypeAdapter) {
            return new VerboseTypeAdapter<>(propertyName, delegateTypeAdapter)
                    // A convenient method to simplify null-handling
                    .nullSafe();
        }

        @Override
        @SuppressWarnings("resource")
        public void write(final JsonWriter out, final T object)
                throws IOException {
            // Open the object with `{`
            out.beginObject();
            // Prepend the object with its reserved name
            out.name(propertyName);
            // Write the object
            delegateTypeAdapter.write(out, object);
            // And close the object with `}`
            out.endObject();
        }

        @Override
        public T read(final JsonReader in)
                throws IOException {
            // Assume the very first token is `{`
            in.beginObject();
            // Peeking what's the actual property name
            final String actualPropertyName = in.nextName();
            // And if it's not we expect, throw a JSON parse exception
            if ( !actualPropertyName.equals(propertyName) ) {
                throw new JsonParseException("Expected " + propertyName + " but was " + actualPropertyName);
            }
            // Otherwise read the value led by the property name
            final T object = delegateTypeAdapter.read(in);
            // And make sure there are no more properties
            if ( in.hasNext() ) {
                throw new JsonParseException(propertyName + " is expected to be the only top-most property");
            }
            // Assume the very last token is `}` (this works for the check above, but we made it more semantical)
            in.endObject();
            return object;
        }

    }

}

因此,例如,以下代码

代码语言:javascript
复制
private static final Gson gson = new GsonBuilder()
        .setFieldNamingStrategy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
        .registerTypeAdapterFactory(VerboseTypeAdapterFactory.get(ImmutableMap.of(UserDetails.class, "user")))
        .create();

...

final UserDetails userDetails = gson.fromJson(jsonReader, UserDetails.class);
System.out.println(userDetails.name);
System.out.println(userDetails.email);
System.out.println(userDetails.timeZone);
final String json = gson.toJson(userDetails);
System.out.println(json);

产生

代码语言:javascript
复制
username
blah@blah.com
America/New_York
{"user":{"name":"username","email":"blah@blah.com","time_zone":"America/New_York"}}

作为结论:

  • 不再有过多的Gson实例化。
  • 继承的原始Gson实例配置(即FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES设置一次)。
  • 没有中间JsonElement实例。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49456712

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档