gpt4 book ai didi

java - Gson:反序列化一个计算值

转载 作者:行者123 更新时间:2023-11-30 06:47:49 26 4
gpt4 key购买 nike

如何让 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();
}

deserializefalse时,我得到size = 0;当 deserializetrue 时,我得到 size = old_size

有没有办法“强制”重新计算?

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

最佳答案

发生这种情况是因为 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());
}

临时测试的使用示例:

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");
}

输出:

{"members":["Foo","Bar","Baz"],"size":3}
SUCCESS

查看更多:

关于java - Gson:反序列化一个计算值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43359657/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com