【问题标题】:How to serialize nested ObjectId to String with Jackson?如何使用 Jackson 将嵌套的 ObjectId 序列化为 String?
【发布时间】:2016-04-08 08:27:53
【问题描述】:

有manyquestions 与杰克逊有关从ObjectId 到String 的转换。所有答案都建议创建自己的JsonSerializer<ObjectId> 或使用@JsonSerialize(using = ToStringSerializer.class) 注释ObjectId 字段。

但是,我有一张有时包含ObjectIds的地图,即:

class Whatever {
  private Map<String, Object> parameters = new HashMap<>();
  Whatever() {
    parameters.put("tom", "Cat");
    parameters.put("jerry", new ObjectId());
  }
}

我想让杰克逊把它转换成:

{
  "parameters": {
    "tom": "cat",
    "jerry": "57076a6ed1c5d61930a238c5"
  }
}

但我明白了:

{
  "parameters": {
    "tom": "cat",
    "jerry": {
      "date": 1460103790000,
      "machineIdentifier": 13747670,
      "processIdentifier": 6448,
      "counter": 10631365,
      "time": 1460103790000,
      "timestamp": 1460103790,
      "timeSecond": 1460103790
    }
  }
}

我已经用

注册了转换(在 Spring 中)
public class WebappConfig extends WebMvcConfigurerAdapter {
  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder
        .serializerByType(ObjectId.class, new ToStringSerializer());
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build());
    converters.add(converter);
  }
}

并且第一级ObjectIds转换正确。如何让杰克逊也转换嵌套的?我必须为此地图编写自定义转换器吗?

请记住,这个Map 可以嵌套多次(即包含另一个地图)。每当杰克逊看到它时,我只想将ObjectId 转换为String。

【问题讨论】:

    标签: java json spring jackson


    【解决方案1】:

    我想你从org.springframework.boot:spring-boot-starter-data-mongodb 中获取了大约org.bson.types.ObjectId。你的代码对我来说非常好。我能看到的一件事是您没有在WebappConfig 上方显示@Configuration 注释。

    这是我的演示项目,你能在你的设置上测试它吗?

    Application.java

    import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
    import org.bson.types.ObjectId;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
        @Configuration
        public static class WebappConfig extends WebMvcConfigurerAdapter {
            @Override
            public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
                builder
                        .serializerByType(ObjectId.class, new ToStringSerializer());
                MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build());
                converters.add(converter);
            }
        }
    
        @RestController
        public static class MyRestController {
    
            @ResponseBody
            @RequestMapping("/")
            public Whatever method() {
                return new Whatever();
            }
        }
    
        public static class Whatever {
            private Map<String, Object> parameters = new HashMap<>();
    
            public Whatever() {
                parameters.put("tom", "Cat");
                parameters.put("jerry", new ObjectId());
            }
    
            public Map<String, Object> getParameters() {
                return parameters;
            }
    
            public void setParameters(Map<String, Object> parameters) {
                this.parameters = parameters;
            }
        }
    }
    

    来自 127.0.0.1:8080 的响应

    {
      "parameters": {
        "tom": "Cat",
        "jerry": "5709df1cf0d9550b4de619d2"
      }
    }
    

    Gradle:

    dependencies {
        compile("org.springframework.boot:spring-boot-starter-data-mongodb")
        compile("org.springframework.boot:spring-boot-starter-web")
    }
    

    【讨论】:

    • 我创建了一个minimal not working example,它也为我正确映射。看来我必须更仔细地调查这个问题。感谢您检查此内容,如果我发现了什么,我会发布更新。
    • 我现在可以确认这是应用程序其他地方的错误。 Map 由来自 jackson 的对象映射器的另一个实例转换,而不是在 Spring 上下文中使用的实例。它没有应用ObjectId 配置,因此无法工作。感谢您强迫 be 创建一个最小的示例,并为我的错误道歉!
    • 我尝试运行上面发布的 Application.java,但没有成功。使用此处描述的 @JsonSerialize 注释虽然有效:imalhasaranga.com/2014/07/20/238
    【解决方案2】:

    感谢 varren 的回答,它在 springMvc 的旧版本中运行良好。 但自 5.0 起,WebMvcConfigurerAdapter 已被弃用。 解决方案:

    1. 可能不行 解决方法:我们可以直接实现 WebMvcConfigurer 来进行 mvc 配置。但有些配置可能不起作用,因为 WebMvcConfigurationSupport 的优先级更高。
    2. 建议解决方案:我们可以直接扩展WebMvcConfigurationSupport。暗示configureMessageConverters 方法可以添加我们需要的各种自定义HttpMessageConverters,并且在默认转换器之前可以正常工作。

    spring 框架是一个了不起的框架,有时间我需要深入研究一下。(●'◡'●)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      • 2013-01-01
      • 1970-01-01
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多