如何将 JSON 对象数组反序列化为 JSON 字符串数组?

huangapple 未分类评论47阅读模式
英文:

How deserialize json object array as array of json strings?

问题

考虑 JSON 输入:

{
    "companies": [
        {
            "id": 1,
            "name": "name1"
        },
        {
            "id": 1,
            "name": "name1"
        }
    ],
    "nextPage": 2
}

如何将其反序列化为以下类:

public class MyClass {
    List<String> companies;
    Integer nextPage;
}

其中 List<String> companies; 包含以下字符串:

{"id": 1, "name": "name1"}
{"id": 1, "name": "name1"}

@JsonRawValue 对于 List<String> companies; 不起作用。

是否有一种方法可以配置 Jackson 序列化,只使用注解将 companies 数组保留为原始 JSON 字符串?(例如,不编写自定义反序列化器)

英文:

Consider json input:

{
    companies: [
        {
            &quot;id&quot;: 1,
            &quot;name&quot;: &quot;name1&quot;
        },
        {
            &quot;id&quot;: 1,
            &quot;name&quot;: &quot;name1&quot;
        }
    ],
    nextPage: 2
}

How deserialize this into class:

public class MyClass {
    List&lt;String&gt; companies;
    Integer nextPage;
}

Where List&lt;String&gt; companies; consists of strings:

{&quot;id&quot;: 1,&quot;name&quot;: &quot;name1&quot;}
{&quot;id&quot;: 1,&quot;name&quot;: &quot;name1&quot;}

@JsonRawValue doesn't work for List&lt;String&gt; companies;

Is there a way to configure Jackson serialization to keep companies array with raw json string with annotations only? (E.g. without writing custom deserializator)

答案1

得分: 0

以下是翻译好的内容:

没有仅使用注解的解决方案来解决您的问题。不过您需要将 JSON 对象转换为 java.lang.String,并且需要指定该转换。

您可以:

  1. 编写自定义反序列化器,这可能是最明显的解决方案,但在问题中被禁止。
  2. 注册自定义的 com.fasterxml.jackson.databind.deser.DeserializationProblemHandler,并以更复杂的方式处理 com.fasterxml.jackson.databind.exc.MismatchedInputException 的情况。
  3. 实现 com.fasterxml.jackson.databind.util.Converter 接口,将 JsonNode 转换为 String。这是一种半注解化的解决问题的方式,但我们没有实现最糟糕的部分 - 反序列化。

现在来看看第二种解决方案。

  1. DeserializationProblemHandler

解决方案相当简单:

ObjectMapper mapper = new ObjectMapper();
mapper.addHandler(new DeserializationProblemHandler() {
    @Override
    public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg) throws IOException {
        if (targetType.getRawClass() == String.class) {
            // 以树状结构读取并转换为字符串
            return p.readValueAsTree().toString();
        }
        return super.handleUnexpectedToken(ctxt, targetType, t, p, failureMsg);
    }
});

将整个 JSON 作为 TreeNode 读取,并使用 toString 方法将其转换为 String。幸运的是,toString 生成有效的 JSON。不足之处是,该解决方案对于给定的 ObjectMapper 实例具有全局范围。

  1. 自定义转换器

此解决方案需要实现 com.fasterxml.jackson.databind.util.Converter 接口,将 com.fasterxml.jackson.databind.JsonNode 转换为 String

class JsonNode2StringConverter implements Converter<JsonNode, String> {
    @Override
    public String convert(JsonNode value) {
        return value.toString();
    }

    @Override
    public JavaType getInputType(TypeFactory typeFactory) {
        return typeFactory.constructType(new TypeReference<JsonNode>() {
        });
    }

    @Override
    public JavaType getOutputType(TypeFactory typeFactory) {
        return typeFactory.constructType(new TypeReference<String>() {
        });
    }
}

现在,您可以像下面这样使用注解:

@JsonDeserialize(contentConverter = JsonNode2StringConverter.class)
private List<String> companies;

解决方案 2 和 3 几乎以相同的方式解决了这个问题 - 读取节点并将其转换回 JSON,但使用了不同的方法。

如果您想避免反序列化和序列化过程,您可以查看本文中提供的解决方案:使用Jackson将JSON属性反序列化为String,并参考以下内容:

英文:

There is no annotation-only solution for your problem. Somehow you have to convert JSON Object to java.lang.String and you need to specify that conversion.

You can:

  1. Write custom deserializer which is probably most obvious solution but forbidden in question.
  2. Register custom com.fasterxml.jackson.databind.deser.DeserializationProblemHandler and handle com.fasterxml.jackson.databind.exc.MismatchedInputException situation in more sophisticated way.
  3. Implement com.fasterxml.jackson.databind.util.Converter interface and convert JsonNode to String. It is semi-annotational way to solve a problem but we do not implement the worst part - deserialisation.

Let's go to point 2. right away.

  1. DeserializationProblemHandler

Solution is pretty simple:

ObjectMapper mapper = new ObjectMapper();
mapper.addHandler(new DeserializationProblemHandler() {
	@Override
	public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken t, JsonParser p, String failureMsg) throws IOException {
		if (targetType.getRawClass() == String.class) {
			// read as tree and convert to String
			return p.readValueAsTree().toString();
		}
		return super.handleUnexpectedToken(ctxt, targetType, t, p, failureMsg);
	}
});

Read a whole piece of JSON as TreeNode and convert it to String using toString method. Helpfully, toString generates valid JSON. Downside, this solution has a global scope for given ObjectMapper instance.

  1. Custom Converter

This solution requires to implement com.fasterxml.jackson.databind.util.Converter interface which converts com.fasterxml.jackson.databind.JsonNode to String:

class JsonNode2StringConverter implements Converter&lt;JsonNode, String&gt; {
	@Override
	public String convert(JsonNode value) {
		return value.toString();
	}

	@Override
	public JavaType getInputType(TypeFactory typeFactory) {
		return typeFactory.constructType(new TypeReference&lt;JsonNode&gt;() {
		});
	}

	@Override
	public JavaType getOutputType(TypeFactory typeFactory) {
		return typeFactory.constructType(new TypeReference&lt;String&gt;() {
		});
	}
}

and now, you can use annotation like below:

@JsonDeserialize(contentConverter = JsonNode2StringConverter.class)
private List&lt;String&gt; companies;

Solutions 2. and 3. solve this problem almost in the same way - read node and convert it back to JSON, but uses different approaches.

If, you want to avoid deserialising and serialising process you can take a look on solution provided in this article: Deserializing JSON property as String with Jackson and take a look at:

huangapple
  • 本文由 发表于 2020年4月7日 17:52:43
  • 转载请务必保留本文链接:https://java.coder-hub.com/61077279.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定