是否可以让 Jackson 将嵌套对象序列化为字符串

2023-11-27

鉴于这些课程:

@Value
private static class Message {
    private final String type;
    private final MyType message;
}

@Value
public class MyType {
    private final String foo;
}

杰克逊将制作:

{
  "Type" : "Test",
  "Message" : {"foo" : "bar"}
}

我是否可以向 Jackson 提供某种类型的注释或指令,要求其将嵌套的复杂类型序列化为字符串,例如所需的 JSON 为:

{
  "Type" : "Test",
  "Message" : "{\"foo\" : \"bar\"}"
}

我在消息字段上尝试了这两个注释:

 @JsonFormat(shape = JsonFormat.Shape.STRING)
 @JsonSerialize(as=String.class)

两者都没有达到预期的效果。现在我的“黑客”是在构建时执行此操作:

return new Message("Test", mapper.writeValueAsString(new MyType("bar")));

我想我可以编写一个自定义序列化器,但我想知道这是否是内置的某种类型的标准行为。我的用例是我正在构建一个JSON有效负载预计包含一个字符串消息,该消息本身包含JSON.

环境

Jackson 版本是 2.9.0,在 Java 10 上使用 Spring Boot 2。


可以使用自定义序列化器来完成:

class EscapedJsonSerializer extends StdSerializer<Object> {
    public EscapedJsonSerializer() {
        super((Class<Object>) null);
    }


    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        StringWriter str = new StringWriter();
        JsonGenerator tempGen = new JsonFactory().setCodec(gen.getCodec()).createGenerator(str);
        if (value instanceof Collection || value.getClass().isArray()) {
            tempGen.writeStartArray();
            if (value instanceof Collection) {
                for (Object it : (Collection) value) {
                    writeTree(gen, it, tempGen);
                }
            } else if (value.getClass().isArray()) {
                for (Object it : (Object[]) value) {
                    writeTree(gen, it, tempGen);
                }
            }
            tempGen.writeEndArray();
        } else {
            provider.defaultSerializeValue(value, tempGen);
        }
        tempGen.flush();
        gen.writeString(str.toString());
    }


    @Override
    public void serializeWithType(Object value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
        StringWriter str = new StringWriter();
        JsonGenerator tempGen = new JsonFactory().setCodec(gen.getCodec()).createGenerator(str);
        writeTree(gen, value, tempGen);
        tempGen.flush();
        gen.writeString(str.toString());
    }

    private void writeTree(JsonGenerator gen, Object it, JsonGenerator tempGen) throws IOException {
        ObjectNode tree = ((ObjectMapper) gen.getCodec()).valueToTree(it);
        tree.set("@class", new TextNode(it.getClass().getName()));
        tempGen.writeTree(tree);
    }
}

和解串器:

class EscapedJsonDeserializer extends JsonDeserializer<Object> implements ContextualDeserializer {
    private final Map<JavaType, JsonDeserializer<Object>> cachedDeserializers = new HashMap<>();

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        throw new IllegalArgumentException("EscapedJsonDeserializer should delegate deserialization for concrete class");

    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        JavaType type = (ctxt.getContextualType() != null) ?
                ctxt.getContextualType() : property.getMember().getType();
        return cachedDeserializers.computeIfAbsent(type, (a) -> new InnerDeserializer(type));
    }

    private class InnerDeserializer extends JsonDeserializer<Object> {
        private final JavaType javaType;

        private InnerDeserializer(JavaType javaType) {
            this.javaType = javaType;
        }

        @Override
        public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            String string = p.readValueAs(String.class);
            return ((ObjectMapper) p.getCodec()).readValue(string, javaType);
        }

        @Override
        public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer)
                throws IOException {

            String str = p.readValueAs(String.class);


            TreeNode root = ((ObjectMapper) p.getCodec()).readTree(str);
            Class clz;
            try {
                clz = Class.forName(((TextNode) root.get("@class")).asText());
                Object newJsonNode = p.getCodec().treeToValue(root, clz);
                return newJsonNode;
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

该字段应使用 @JsonSerialize 和 @JsonDeserialize 进行注释(如果需要)

class Outer {
    @JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS)
    @JsonSerialize(using = EscapedJsonSerializer.class)
    @JsonDeserialize(using = EscapedJsonDeserializer.class)
    public Foo val;
}

它适用于简单的集合(列表、数组),并且在某种程度上适用于多态性,尽管对于特定的多态性相关问题可能需要更复杂的解决方案。 示例输出如下所示:

{"val":"{\"foo\":\"foo\",\"@class\":\"org.test.Foo\"}"}
{"val":"{\"foo\":\"foo\",\"bar\":\"bar\",\"@class\":\"org.test.Bar\"}"}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以让 Jackson 将嵌套对象序列化为字符串 的相关文章

随机推荐

  • 通过 jQuery 添加的脚本标签在 FireBug 中不可见

    我正在添加
  • Spring data JPA 原生查询跳过锁定

    我想执行一个SKIP LOCKED使用 Spring Data JPA 对 Oracle 进行查询 所以我尝试了以下操作 Lock LockModeType PESSIMISTIC WRITE Query value SELECT FROM
  • 更新数据库 Android

    谁能告诉我如何更新android中的数据库 我创建了一个带有嵌入式数据库的应用程序 我更改了清单中数据库的版本并创建了更新方法 我想测试它以查看数据库是否正确更新 但是当我使用 adb 命令时 只有 r 允许我重新安装 但它会保留数据库 有
  • SignalR 2.0.2 创建持久连接

    我使用包管理器控制台将 SignalR 2 0 2 安装到我的 MVC 4 5 应用程序中 我做了连接配置的标准示例 namespace SignalRPersistent public class Startup public void
  • 如何在 C# 中使用 XMLREADER 从 XML 字符串读取特定元素

    我有 XML 字符串
  • 当我将 OS X 升级到 10.9 时,我的 applescript 不再工作

    以下代码尝试打开代理设置对话框 NSAppleScript a NSAppleScript alloc initWithSource tell application System Preferences nset current pane
  • jQuery - 垂直向上切换(即不是向下)

    我需要创建一个向上而不是向下动画的切换 换句话说 与 正常 切换相反 也许更简单的是 切换应该在菜单项 它是一个菜单 上方向上滑动以变得可见 而不是像普通的 SlideToggle 等那样向下滑动 我已经快到了 var opened fal
  • SYSMALLOC:断言失败 - 关于如何有效调试的任何想法?

    我的服务器守护进程在大多数机器上运行良好 但在我得到的一台机器上 malloc c 3074 sYSMALLOc Assertion old top mbinptr char av gt bins 1 1 2 builtin offseto
  • Java继承

    为什么最后打印的是 我是一个儿童班 public class Parent String parentString public Parent System out println Parent Constructor public Par
  • jQuery 无限函数执行

    我们想知道是否可以有一个使用 jQuery 的函数来检查多个元素 并根据通过单击分配给它们的类型来执行其他函数 基本上 这是一个将永远运行的函数 而用户不会刷新页面 这个想法不是依赖事件点击来执行功能 而是依赖分配给特定元素的类 例如 td
  • 如何在 Java 日期和儒略日数之间进行转换? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 Java 怎样才能Date被转换成double代表儒略日 如何将儒略日数转换为JavaD
  • 如何更改 xtable markdown 中某些单元格的颜色?

    我有一个名为 j 的数据框 dput j structure list Trans c 89 8 3337 NA 97 55 NA 3558 7 NA 4290 6 NA 65 95 94 55 3495 9 CPU c 6 938 79
  • 无法在 Google App Engine 上部署 java 项目

    我已在 Google App Engine 上创建了一个项目 但无法使用项目 id 部署该项目 我的项目 id 以下是发生问题的详细信息 您选择的应用程序 ID 我的项目 ID 不存在 去http cloud google com cons
  • 重新加载 Bootstrap 自定义

    On http getbootstrap com customize 可以创建和下载自定义引导程序配置 下载中包含一个名为 config json 的文件 是否可以以某种方式使用该文件来重新填充值并调整自定义引导配置 如果没有 有人知道为什
  • CodeIgniter 调用模型如何查看?

    我有一个包含数据表的视图 该数据是在模型上生成的 我如何在我的视图中调用此模型以发布在我的视图上 这相当于我想在 php 上使用 codeIgniter 做的事情 while row mysql fetch array requet cod
  • Laravel 每日日志使用错误的权限创建

    我有一个使用 php artisan 运行的脚本 带有rootuser 有时它会导致每日日志文件在apache之前创建www data用户这样做 这意味着当真正的用户使用我的网络应用程序时 我收到文件夹权限错误 无法打开流 权限被拒绝 我将
  • int (*p) [4]?

    int p 4 p 指针是指向 4 个整数的数组吗 或者是什么 以及如何为该指针调用 新 p 指针是指向 4 个整数的数组吗 Correct 我怎样才能为这个指针调用 new 例如 p new int 7 4
  • Canvas getImageData() 以获得最佳性能。提取所有数据还是一次提取一个数据?

    我需要扫描画布图像中的每个像素 并对颜色等进行一些处理 为了获得最佳性能 我是否应该一次性获取所有数据并通过数组对其进行处理 或者我应该在处理每个像素时调用它 所以基本上 data context getImageData x y heig
  • jQuery ajax 循环内问题

    这个js循环脚本总是获取jquery ajax函数内ui item的最后一个值 如何捕获每次迭代的正确值 for var i 0 i lt split files cb value holder length 1 i var split v
  • 是否可以让 Jackson 将嵌套对象序列化为字符串

    鉴于这些课程 Value private static class Message private final String type private final MyType message Value public class MyTy