Ben*_*n M 5 java base64 json jackson jackson-databind
有没有一种简单的方法可以使用 Jackson 将对象序列化为 base64 编码的 JSON?(对象 -> JSON -> base64)
我尝试使用自定义StdSerializer,但这(当然)会导致无限循环:
class MySerializer extends StdSerializer<Foo> {
public void serialize(Foo value, JsonGenerator gen, SerializerProvider provider) {
StringWriter stringWriter = new StringWriter();
JsonGenerator newGen = gen.getCodec().getFactory().createGenerator(stringWriter);
gen.getCodec().getFactory().getCodec().writeValue(newGen, value);
String json = stringWriter.toString();
String base64 = new String(Base64.getEncoder().encode(json.getBytes()));
gen.writeString(base64);
}
}
Run Code Online (Sandbox Code Playgroud)
解决方法是将所有字段复制到另一个类并使用该类作为中间表示:
class TmpFoo {
public String field1;
public int field2;
// ...
}
class MySerializer extends StdSerializer<Foo> {
public void serialize(Foo value, JsonGenerator gen, SerializerProvider provider) {
TmpFoo tmp = new TmpFoo();
tmp.field1 = value.field1;
tmp.field2 = value.field2;
// etc.
StringWriter stringWriter = new StringWriter();
JsonGenerator newGen = gen.getCodec().getFactory().createGenerator(stringWriter);
gen.getCodec().getFactory().getCodec().writeValue(newGen, tmp); // here "tmp" instead of "value"
String json = stringWriter.toString();
String base64 = new String(Base64.getEncoder().encode(json.getBytes()));
gen.writeString(base64);
}
}
Run Code Online (Sandbox Code Playgroud)
创建 anew ObjectMapper是不需要的,因为我需要默认 ObjectMapper 的所有注册模块和序列化器。
我希望有一些更简单的方法来实现这一目标。
第 1 步:Java 对象
class Foo {
String field1 = "foo";
int field2 = 42;
}
Run Code Online (Sandbox Code Playgroud)
第 2 步:JSON
{"field1":"foo","field2":42}
Run Code Online (Sandbox Code Playgroud)
步骤 3:Base64
eyJmaWVsZDEiOiJmb28iLCJmaWVsZDIiOjQyfQ==
Run Code Online (Sandbox Code Playgroud)
根据此站点,有一种解决方法可以避免此递归问题:
当我们定义自定义序列化器时,Jackson 在内部覆盖原始 BeanSerializer 实例 [...] 我们的 SerializerProvider 每次都会找到自定义序列化器,而不是默认序列化器,这会导致无限循环。
一种可能的解决方法是使用 BeanSerializerModifier 在 Jackson 内部覆盖它之前存储类型文件夹的默认序列化器。
如果我正确理解了解决方法,您的解决方法Serializer应该如下所示:
class FooSerializer extends StdSerializer<Foo> {
private final JsonSerializer<Object> defaultSerializer;
public FooSerializer(JsonSerializer<Object> defaultSerializer) {
super(Foo.class);
this.defaultSerializer = defaultSerializer;
}
@Override
public void serialize(Foo value, JsonGenerator gen, SerializerProvider provider) throws IOException {
StringWriter stringWriter = new StringWriter();
JsonGenerator tempGen = provider.getGenerator().getCodec().getFactory().createGenerator(stringWriter);
defaultSerializer.serialize(value, tempGen, provider);
tempGen.flush();
String json = stringWriter.toString();
String base64 = new String(Base64.getEncoder().encode(json.getBytes()));
gen.writeString(base64);
}
}
Run Code Online (Sandbox Code Playgroud)
除了序列化器之外,还需要一个修饰符:
public class FooBeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getBeanClass().equals(Foo.class)) {
return new FooSerializer((JsonSerializer<Object>) serializer);
}
return serializer;
}
}
Run Code Online (Sandbox Code Playgroud)
示例模块:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setSerializerModifier(new FooBeanSerializerModifier());
mapper.registerModule(module);
Run Code Online (Sandbox Code Playgroud)
编辑:
我已经添加flush()了刷新JsonGenerator tempGen. 另外,我使用 JUnit 创建了一个最小的测试环境,它验证了您的示例: github 存储库可以在此处Foo找到。
编辑:替代方案 2
另一个(简单)选项是使用带有泛型的包装类:
public class Base64Wrapper<T> {
private final T wrapped;
private Base64Wrapper(T wrapped) {
this.wrapped = wrapped;
}
public T getWrapped() {
return this.wrapped;
}
public static <T> Base64Wrapper<T> of(T wrapped) {
return new Base64Wrapper<>(wrapped);
}
}
Run Code Online (Sandbox Code Playgroud)
public class Base64WrapperSerializer extends StdSerializer<Base64Wrapper> {
public Base64WrapperSerializer() {
super(Base64Wrapper.class);
}
@Override
public void serialize(Base64Wrapper value, JsonGenerator gen, SerializerProvider provider) throws IOException {
StringWriter stringWriter = new StringWriter();
JsonGenerator tempGen = provider.getGenerator().getCodec().getFactory().createGenerator(stringWriter);
provider.defaultSerializeValue(value.getWrapped(), tempGen);
tempGen.flush();
String json = stringWriter.toString();
String base64 = new String(Base64.getEncoder().encode(json.getBytes()));
gen.writeString(base64);
}
}
Run Code Online (Sandbox Code Playgroud)
一个示例用例是:
final ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(new Base64WrapperSerializer());
mapper.registerModule(module);
final Foo foo = new Foo();
final Base64Wrapper<Foo> base64Wrapper = Base64Wrapper.of(foo);
final String base64Json = mapper.writeValueAsString(base64Wrapper);
Run Code Online (Sandbox Code Playgroud)
此示例可以在此 GitHub (分支:包装器)存储库中找到,它使用 JUnit 测试验证 foo 示例中的 BASE64 字符串。
| 归档时间: |
|
| 查看次数: |
3404 次 |
| 最近记录: |