在某些情况下,对象可能需要以不同的方式进行序列化。具体来说,一个REST端点正在接受一个标头,如果标头为true,则我们以一种方式进行序列化,如果为false,则以另一种方式进行序列化。我认为,如果我们将header属性放在对象中,那么自定义序列化程序可能会非常适合此操作,但是使用它会遇到一些麻烦。
(请注意,由于使用了一些泛型以及代码的结构方式,仅创建一个不同的对象将需要大量重构,因此我试图找到一种更快的解决方案。)
例如,我的序列化器如下所示:
public class FooSerializer extends StdSerializer<Foo>
{
@Override
public void serialize(
final Foo foo,
final JsonGenerator jsonGenerator,
final SerializerProvider serializerProvider)
throws IOException
{
if (foo.isFlattened())
{
jsonGenerator.writeObject(flatten(foo));
}
else
{
jsonGenerator.writeObject(foo);
}
}
private Map<String,Object> flatten(Foo foo)
{
// ... some logic that builds the Map...
}
}
将对序列化的类进行相应的注释:
@JsonSerialize(using = FooSerializer.class)
public class Foo
{
// ... things...
}
问题几乎立即变得很明显:jsonGenerator.writeObject
调用ObjectMapper
来序列化对象...然后将再次调用我的序列化器,这给了我们一个可爱的无限循环,并最终导致了堆栈溢出。 / p>
要解决此问题,我唯一想到的选择是使用反射,遍历对象的属性,然后使用jsonGenerator
将其写入新对象。这感觉有点过头了,特别是当杰克逊应该能够为我做的时候。问题是我找不到告诉ObjectMapper
忽略类上的序列化程序的方法。
是否有更好的方法?我在想我可以创建一个自定义ObjectMapper
,以某种方式忽略类中注释的序列化程序,并将其用作jsonGenerator
的编解码器...但不完全确定要使用哪种杠杆ObjectMapper
。
答案 0 :(得分:0)
怀疑,有一种方法可以禁用特定注释。在这种情况下,我想在JsonSerialize
类上禁用Foo
注释。因此,我这样做是为了打破无限循环:
public class FooSerializer extends StdSerializer<Foo>
{
@Override
public void serialize(
final Foo foo,
final JsonGenerator jsonGenerator,
final SerializerProvider serializerProvider)
throws IOException
{
ObjectMapper mapper = new ObjectMapper();
JacksonAnnotationIntrospector annotationIntrospector =
new JacksonAnnotationIntrospector()
{
@Override
protected <A extends Annotation> A _findAnnotation(
final Annotated annotated,
final Class<A> annotationClass)
{
if (annotated.hasAnnotation(JsonSerialize.class) &&
annotated.getRawType() == Foo.class)
{
return null;
}
return super._findAnnotation(annotated, annotationClass);
}
};
mapper.setAnnotationIntrospector(annotationIntrospector);
jsonGenerator.setCodec(mapper);
if (foo.isFlattened())
{
jsonGenerator.writeObject(flatten(foo));
}
else
{
jsonGenerator.writeObject(foo);
}
}
private Map<String,Object> flatten(Foo foo)
{
// ... some logic that builds the Map...
}
}
答案 1 :(得分:0)
user_id
允许以多种不同方式注册自定义序列化程序。其中之一是使用Jackson
类,该类允许创建自定义序列化程序,但是如果需要,我们也可以使用那里可用的基本序列化程序。
上述问题似乎是com.fasterxml.jackson.databind.ser.BeanSerializerModifier
问题的一个很好的例子,在这里我们可以解耦OOP
,这是逻辑和序列化过程。序列化程序不应该知道如何将对象转换为POJO
。它应该只具有序列化逻辑。让我们介绍Map
和序列化程序使用的接口:
POJO
现在,我们可以通过实现interface Flattenable {
boolean isFlattened();
Map<String, Object> flatten();
}
class Foo implements Flattenable {
private boolean flattened;
private int id;
public Foo(boolean flattened, int id) {
this.flattened = flattened;
this.id = id;
}
@Override
public Map<String, Object> flatten() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("id", getId());
map.put("random", ThreadLocalRandom.current().nextDouble());
return map;
}
@Override
public boolean isFlattened() {
return flattened;
}
public void setFlattened(boolean flattened) {
this.flattened = flattened;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
接口来轻松处理其他类型。序列化逻辑将是相同的。自定义序列化器可能如下所示:
Flattenable
有了class FlattenableJsonSerializer extends JsonSerializer<Flattenable> {
private final JsonSerializer<Object> base;
public FlattenableJsonSerializer(JsonSerializer base) {
this.base = Objects.requireNonNull(base);
}
@Override
public void serialize(Flattenable value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value.isFlattened()) {
gen.writeObject(value.flatten());
} else {
base.serialize(value, gen, serializers);
}
}
}
模型和序列化程序后,我们只需配置POJO
并尝试使用我们的解决方案:
ObjectMapper
以上代码显示两行:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
public class JsonFlattenApp {
public static void main(String[] args) throws Exception {
SimpleModule flattenModule = new SimpleModule("FlattenModule");
flattenModule.setSerializerModifier(new FlattenableBeanSerializerModifier());
ObjectMapper mapper = JsonMapper.builder()
.addModule(flattenModule)
.build();
System.out.println(mapper.writeValueAsString(new Foo(true, 1)));
System.out.println(mapper.writeValueAsString(new Foo(false, 2)));
}
}
class FlattenableBeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (Flattenable.class.isAssignableFrom(beanDesc.getBeanClass())) {
return new FlattenableJsonSerializer(serializer);
}
return serializer;
}
}