Gson:反序列化计算值

时间:2017-04-12 03:17:41

标签: java gson

如何让Gson反序列化计算值?

这是一个过于简单的例子:

@SerializedName("members")
@Expose
private final List<String> members;

@SerializedName("size")
@Expose(serialize = true, deserialize = false)
private final int size;

public Club(List<String> members) {
    this.members = members;
    this.size = members.size();
}

sizedeserialize时,我false = 0; sizedeserialize时,我会true = old_size

有没有办法强迫&#34;强迫&#34;重新计算?

我知道我可以在getter中执行此操作

1 个答案:

答案 0 :(得分:1)

这是因为Gson在反序列化期间不调用构造函数。 但是,可以拦截实例化后的对象阶段,并对最近反序列化的对象进行一些额外的操作。

以下是一个示例@PostConstruct - 知晓型适配器工厂:

final class PostConstructTypeAdapterFactory
        implements TypeAdapterFactory {

    // No intermediate state, can be a singleton
    private static final TypeAdapterFactory postConstructTypeAdapterFactory = new PostConstructTypeAdapterFactory();

    private PostConstructTypeAdapterFactory() {
    }

    // However, making the constructor private encapsulates the way it's instantiated
    static TypeAdapterFactory getPostConstructTypeAdapterFactory() {
        return postConstructTypeAdapterFactory;
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final List<Method> postConstructMethods = getPostConstructMethods(typeToken.getRawType());
        if ( postConstructMethods.isEmpty() ) {
            // If no post-construct methods found, just let Gson to pick up the next best-match type adapter itself
            return null;
        }
        // Obtain the "original" type adapter
        final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
        return new PostConstructTypeAdapter<>(delegateTypeAdapter, postConstructMethods);
    }

    private static List<Method> getPostConstructMethods(final Class<?> clazz) {
        if ( clazz.isPrimitive() ) {
            // Nothing to do with primitives
            return emptyList();
        }
        // The following stream operation collects all `@PostConstruct` methods
        // from java.lang.Object to the concrete class
        // where all @PostConstruct methods must satisfy the following conditions (differ from the original `@PostConstruct` contract):
        // * have no paramaters
        // * return nothing (but it looks like a too strict limitation, though)
        // * be annotated with `@PostConstruct`
        return superToSub(clazz)
                .stream()
                .flatMap(c -> Stream.of(c.getDeclaredMethods()))
                .filter(m -> {
                    final int parameterCount = m.getParameterCount();
                    if ( parameterCount != 0 ) {
                        return false;
                    }
                    final Class<?> returnType = m.getReturnType();
                    if ( returnType != void.class ) {
                        return false;
                    }
                    return m.isAnnotationPresent(PostConstruct.class);
                })
                .peek(m -> m.setAccessible(true))
                .collect(toList());
    }

    private static List<Class<?>> superToSub(final Class<?> clazz) {
        final List<Class<?>> hierarchy = subToSuper(clazz);
        Collections.reverse(hierarchy);
        return hierarchy;
    }

    private static List<Class<?>> subToSuper(final Class<?> clazz) {
        final List<Class<?>> hierarchy = new ArrayList<>();
        for ( Class<?> c = clazz; c != null; c = c.getSuperclass() ) {
            hierarchy.add(c);
        }
        return hierarchy;
    }

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

        private final TypeAdapter<T> delegateTypeAdapter;
        private final Iterable<Method> postConstructMethods;

        private PostConstructTypeAdapter(final TypeAdapter<T> delegateTypeAdapter, final Iterable<Method> postConstructMethods) {
            this.delegateTypeAdapter = delegateTypeAdapter;
            this.postConstructMethods = postConstructMethods;
        }

        @Override
        public void write(final JsonWriter out, final T value)
                throws IOException {
            // Nothing special to do on write, so just delegate the job
            delegateTypeAdapter.write(out, value);
        }

        @Override
        public T read(final JsonReader in)
                throws IOException {
            try {
                // Whilst on read there's a need to apply all post-construction methods
                final T read = delegateTypeAdapter.read(in);
                for ( final Method method : postConstructMethods ) {
                    method.invoke(read);
                }
                return read;
            } catch ( IllegalAccessException | InvocationTargetException ex ) {
                throw new IOException(ex);
            }
        }

    }

}

然后,您的Club可以包含一个后构造函数:

@PostConstruct
private void postConstruct()
        throws NoSuchFieldException, IllegalAccessException {
    final Field sizeField = Club.class.getDeclaredField("size");
    sizeField.setAccessible(true);
    sizeField.set(this, members.size());
}

使用ad-hoc测试的示例:

private static final Gson gson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .registerTypeAdapterFactory(getPostConstructTypeAdapterFactory())
        .create();

public static void main(final String... args) {
    final List<String> members = ImmutableList.of("Foo", "Bar", "Baz");
    final Club beforeClub = new Club(members);
    final List<String> beforeMembers = beforeClub.members;
    final int beforeSize = beforeClub.size;
    final String clubJson = gson.toJson(beforeClub);
    System.out.println(clubJson);
    final Club afterClub = gson.fromJson(clubJson, Club.class);
    final List<String> afterMembers = afterClub.members;
    final int afterSize = afterClub.size;
    if ( !beforeMembers.equals(afterMembers) ) {
        throw new AssertionError("`members` values do not match");
    }
    if ( beforeSize != afterSize ) {
        throw new AssertionError("`size` values do not match");
    }
    System.out.println("SUCCESS");
}

输出:

  

{&#34;会员&#34;:[&#34;富&#34;&#34;酒吧&#34;&#34;巴兹&#34],&#34;大小&#34; :3}
  成功

查看更多: