我想创建一个自定义序列化程序,它可以完成一些工作,然后将其余部分用于默认序列化.
例如:
@JsonSerialize(using = MyClassSerializer.class)
public class MyClass {
...
}
public class MyClassSerializer extends JsonSerializer<MyClass> {
@Override
public void serialize(MyClass myClass, JsonGenerator generator,
SerializerProvider provider)
throws JsonGenerationException, IOException {
if (myClass.getSomeProperty() == someCalculationResult) {
provider.setAttribute("special", true);
}
generator.writeObject(myClass);
}
}
Run Code Online (Sandbox Code Playgroud)
有了为聚合对象创建其他自定义序列化程序的想法,这些序列化程序根据'speical'属性值表现不同.但是,上面的代码不起作用,因为毫无疑问会进入无限递归.
有没有办法告诉杰克逊在设置属性后使用默认序列化?我真的不想枚举像许多自定义序列化程序一样的所有属性,因为类相当复杂,我不想每次更改类时都要对序列化程序进行双重维护.
浏览文档和源代码,我没有看到明确的方法来做到这一点.好奇,如果我错过了什么.
假设我从服务器响应中收到一个InputStream.我从这个InputStream创建一个JsonParser.预计服务器响应是包含有效JSON的文本,例如:
{"iamValidJson":"yay"}
但是,如果响应最终是无效的JSON或根本不是JSON,例如:
Some text that is not JSON
JsonParser最终会抛出异常.在这种情况下,我希望能够Some text that is not JSON从JsonParser中提取底层的无效文本" ",以便它可以用于其他目的.
我无法将其从InputStream中拉出来,因为它不支持重置,并且JsonParser的创建会消耗它.
有没有办法做到这一点?
假设我正在为某个类编写自定义序列化,但是希望使用默认方法处理其中一个字段.
怎么做?
虽然序列化我们有JsonGenerator#writeObjectField().
但是反序列化的相应方法是什么?
请注意以下代码:
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.Objects;
public class TryDelegate {
public static class MyOuterClassSerializer extends JsonSerializer<MyOuterClass> {
@Override
public void serialize(MyOuterClass value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeStartObject();
gen.writeObjectField("inner", value.getInner());
gen.writeEndObject();
}
}
public static class MyOuterClassDeserializer extends JsonDeserializer<MyOuterClass> {
@Override
public MyOuterClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
MyOuterClass ans = new MyOuterClass();
JsonToken token;
token = p.getCurrentToken();
if( token != …Run Code Online (Sandbox Code Playgroud) 我猜我有一个父类参数,它有2个子类ComboParameter和IntegerParameter
@JsonSubTypes({
@JsonSubTypes.Type(value = IntegerParameter.class, name = "integerParam"),
@JsonSubTypes.Type(value = ComboParameter.class, name = "comboParam")
})
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.WRAPPER_OBJECT)
public abstract class Parameter {
String regEx;
}
@JsonTypeName("integerParam")
public class IntegerParameter extends Parameter {
}
@JsonTypeName("comboParam")
public class ComboParameter extends Parameter {
List<String> values;
}
Run Code Online (Sandbox Code Playgroud)
我有一个具有属性参数的类
class A {
@JsonUnwrapped
Parameter parameter;
}
Run Code Online (Sandbox Code Playgroud)
对象的序列化A抛出异常
com.fasterxml.jackson.databind.JsonMappingException:未包装的属性需要使用类型信息:无法在不禁用的情况下序列化
SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS
如果我删除注释,@JsonUnwrapped我会有一个像那样的json
{
parameter:{
integerParam:{
regEx: regExVal
}
}
}
Run Code Online (Sandbox Code Playgroud)
而我需要的是像这样的json:
{ …Run Code Online (Sandbox Code Playgroud) 我希望在序列化之前修改对象.我想编写一个自定义序列化程序来解析对象,然后将其传递给默认对象序列化程序.
这就是我所拥有的:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
*
* @author Me
*/
public class PersonSerializer extends JsonSerializer<Person>{
@Override
public void serialize(Person value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
//This returns a modified clone of Person value.
Person safePerson = PrivacyService.getSafePerson(value);
provider.defaultSerializeValue(safePerson, jgen);
}
}
Run Code Online (Sandbox Code Playgroud)
但这只是一个无限循环.我也尝试过:
provider.findTypedValueSerializer(Person.class, true, null).serialize(safePerson, jgen, provider);
Run Code Online (Sandbox Code Playgroud)
这可行,但它不解析对象中的任何字段.
我也试过使用a @JsonFilter但它非常重,并且我的加载时间是六倍.
救命!谢谢!
我有一个外部服务,用于查询一些数据。数据将采用两种格式之一(第一种是“遗留”,但需要支持):
{
"foo": "John Smith"
}
Run Code Online (Sandbox Code Playgroud)
或者
{
"foo": {
"name": "John Smith",
"bar": "baz"
}
}
Run Code Online (Sandbox Code Playgroud)
我想映射到以下 POJO:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Outer {
private Foo foo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Foo {
String name;
String bar;
}
}
Run Code Online (Sandbox Code Playgroud)
第二种格式(foo是一个对象)中的数据应该像任何其他 POJO 一样反序列化,但是给定第一种格式(foo是字符串)中的数据,要将其转换为 的实例Foo,我想调用new Foo(<foo>, null). 为此,我创建了一个自定义解串器(@JsonComponent意味着这个解串器将ObjectMapper通过 JacksonModule接口在 spring 中注册到某种全局):
@JsonComponent
public class FooDeserializer extends JsonDeserializer<Outer.Foo> {
@Override
public Outer.Foo deserialize(JsonParser parser, DeserializationContext …Run Code Online (Sandbox Code Playgroud) 假设有一个具有属性a和三个非抽象子类B,C和D的抽象类A。B没有其他属性,C包含属性c,D包含属性c和d。
我希望将StdDeserializer子类化为抽象类A,以便能够基于要反序列化的属性的存在来决定选择哪个子类。
我之前是从Codehaus发行的Jackson版本中做到这一点的,并且使用以下实现工作正常:
class AbstractADeserializer extends StdDeserializer<A> {
AbstractADeserializer () {
super(A.class);
}
@Override
public A deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
Class<? extends A> requestClass = null;
// root.getFieldNames() is an iterator over all field names
JsonNode cValue = root.findValue("c");
JsonNode dValue = root.findValue("d");
/*
* Check for existence of required fields and choose the
* corresponding request class.
*/
logger.debug(Boolean.toString(c != null)); …Run Code Online (Sandbox Code Playgroud) @Entity
public Product {
@Id
public int id;
public String name;
@ManyToOne(cascade = {CascadeType.DETACH} )
Category category
@ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH} )
Set<Category> secondaryCategories;
}
Run Code Online (Sandbox Code Playgroud)
和这个实体:
@Entity
public Category {
@Id
public int id;
public String name;
}
Run Code Online (Sandbox Code Playgroud)
我希望能够使用 json 发送 POST
{ name: "name", category: 2, secondaryCategories: [3,4,5] }从客户端
并且能够像这样反序列化:
{ name: "name", category: {id: 2 }, secondaryCategories: [{id: 3}, {id: 4}, {id: 5}] }
Run Code Online (Sandbox Code Playgroud)
如果它被发送为
{ name: "name", category: {id: 2 }, secondaryCategories: [{id: 3}, …Run Code Online (Sandbox Code Playgroud) 我有一个像这样的课程
interface IHideable {
boolean isHidden();
}
class Address implements IHideable {
private String city;
private String street;
private boolean hidden;
}
class PersonalInfo implements IHideable {
private String name;
private int age;
private boolean hidden;
}
Run Code Online (Sandbox Code Playgroud)
我想在我的网络服务中序列化 IHideable 列表;但过滤掉隐藏字段设置为 true 的任何对象。
基本上给出了一个对象列表,例如
[
{'city 1','street 1',false},
{'city 2','street 2',true},
{'city 3','street 3',false}
]
Run Code Online (Sandbox Code Playgroud)
我想要的输出为
[
{
city:'city 1',
street:'street 1'
},
{
city:'city 3',
street:'street 3'
}
]
Run Code Online (Sandbox Code Playgroud)
我尝试了以下实现
class ItemSerializer extends JsonSerializer<IHideable> {
@Override
public void serialize(IHideable value, …Run Code Online (Sandbox Code Playgroud) 我有一个这样的请求
{
"varA" : "A",
"varB" : "TCFNhbiBKb3NlMRgwFgYDVQQK"
}
Run Code Online (Sandbox Code Playgroud)
其中 keyvarB是一个 base64 编码的 JSON 字符串。像这样的东西:
{
"nestedVarB1": "some value here",
"nestedVarB2" : "some other value here"
}
Run Code Online (Sandbox Code Playgroud)
我想将它转换成一些 POJO,如下所示:
@Data
public class MyRequest {
private String varA;
private B varB;
}
@Data
public class B {
private String nestedVarB1;
private String nestedVarB2;
}
Run Code Online (Sandbox Code Playgroud)
我经历了几个关于堆栈溢出的解决方案,例如this和thisMyRequest ,但我想通过编写某种 Jackson 反序列化器将 JSON 直接转换为类型的对象。
如何直接将 JSON 转换为MyRequest使用 Jackson 和 Spring Boot?
笔记:
MyRequest和B非常大, …我有一个标准的多态类型Shape,我可以使用标准@JsonTypeInfo机制对其进行多态反序列化:
import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
public class DiscriminatorAliasTest {
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Square.class, name = "square"),
@JsonSubTypes.Type(value = Circle.class, name = "circle")
})
static abstract class Shape {
abstract public String name();
}
static class Square extends Shape {
@JsonProperty("A")
public float width;
@Override
public String name() { return "square"; }
}
static class …Run Code Online (Sandbox Code Playgroud) 所以,标题基本上描述了我需要的东西.比如说,要序列化的bean看起来像这样:
public class SomeBean {
public String someString;
}
Run Code Online (Sandbox Code Playgroud)
我希望Jackson 像这样序列化SomeBean的一个实例:
{
someString: '<the value>',
__hash_someString: '<a proprietary hash of <the value>>'
}
Run Code Online (Sandbox Code Playgroud)
此功能应该是通用的.我不想为SomeBean编写特定的序列化程序,因为这需要在多个位置进行.将" __hash_someString " 添加到类本身不是一个选项,因为它会污染模型.
履行
我希望杰克逊能正常处理豆子.但是当遇到特定的注释(@GenerateHash)时,它应该像之前一样向对象添加另一个字段.所以它想这样:
public class SomeBean {
@GenerateHash
public String someString;
}
Run Code Online (Sandbox Code Playgroud)
这条路到目前为止
有很多类似的主题,但没有一个尝试这样的事情.我并没有真正进入Jackson Serialization的内部工作,但似乎你只能选择修改一个整体的对象.我还没有找到一种方法来拦截字段的序列化过程,只有该字段的值.
我试图使用BeanSerializerModifier实现这一点,并尝试使用@Serializer.但是,我通常最终会陷入无限循环.
我咨询的资源是(不限于):
简而言之, 我怎样才能让杰克逊序列化
public class SomeBean {
@GenerateHash
public String someString;
public String unaffectedString;
}
Run Code Online (Sandbox Code Playgroud)
对此:
{
someString: '<the value>',
__hash_someString: '<a …Run Code Online (Sandbox Code Playgroud) 我想通过扩展默认值并在其后设置更多值来制作我自己的解串器:
simplified code:
public class Dto {
public String originalJsonString;
}
public MyFooDto extends Dto {
public String myField;
}
@Bean
public ObjectMapper deserializingObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(MyFooDto.class, new JsonDtoDeserializer<>());
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
// or maybe instead of the Beam just @JsonDeserialize(using = JsonDtoDeserializer.class) before MyFooDto?
public class JsonDtoDeserializer<T extends Dto> extends StdDeserializer<T> {
// or maybe extends JsonDeserializer? or UntypedObjectDeserializer? or UntypedObjectDeserializer.Vanilla?
public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException …Run Code Online (Sandbox Code Playgroud) jackson ×13
json ×12
java ×11
spring-boot ×3
spring ×2
spring-mvc ×2
android ×1
hash ×1
inputstream ×1
spring-data ×1