这是因为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");
}
输出:
{ “成员”:[ “富”, “酒吧”, “巴兹”], “大小”:3}
SUCCESS
详见:
感谢您的详细回复。这感觉有点复杂,我不明白一些代码,但我会试一试。在getPostConstructMethods()的return语句中,有一个toList()方法。这是未定义的。 .collect()期望收集器参数? – sikidhart
@sikidhart是的,这是一个收集器,这只是一个静态导入的'Collectors.toList'方法。 –