【问题标题】:java spring MappingJacksonJsonView not doing toString on mongodb ObjectIdjava spring MappingJacksonJsonView没有在mongodb ObjectId上做toString
【发布时间】:2012-01-30 14:04:11
【问题描述】:

我在我的 SpringMVC 应用程序中使用 MappingJacksonJsonView 从我的控制器呈现 JSON。我希望对象中的 ObjectId 呈现为 .toString ,而是将 ObjectId 序列化为其部分。它在我的 Velocity/JSP 页面中运行良好:

Velocity:
    $thing.id
Produces:
    4f1d77bb3a13870ff0783c25


Json:
    <script type="text/javascript">
         $.ajax({
             type: 'GET',
             url: '/things/show/4f1d77bb3a13870ff0783c25',
             dataType: 'json',
             success : function(data) {
                alert(data);
             }
         });
    </script>
Produces:
    thing: {id:{time:1327331259000, new:false, machine:974358287, timeSecond:1327331259, inc:-260555739},…}
        id: {time:1327331259000, new:false, machine:974358287, timeSecond:1327331259, inc:-260555739}
            inc: -260555739
            machine: 974358287
            new: false
            time: 1327331259000
            timeSecond: 1327331259
        name: "Stack Overflow"


XML:
    <script type="text/javascript">
         $.ajax({
             type: 'GET',
             url: '/things/show/4f1d77bb3a13870ff0783c25',
             dataType: 'xml',
             success : function(data) {
                alert(data);
             }
         });
    </script>
Produces:
    <com.place.model.Thing>
        <id>
            <__time>1327331259</__time>
            <__machine>974358287</__machine>
            <__inc>-260555739</__inc>
            <__new>false</__new>
        </id>
        <name>Stack Overflow</name>
    </com.place.model.Thing>

有没有办法阻止 MappingJacksonJsonView 从 ObjectId 中获取这么多信息?我只想要 .toString() 方法,而不是所有细节。

谢谢。

添加 Spring 配置:

@Configuration
@EnableWebMvc
public class MyConfiguration {

    @Bean(name = "viewResolver")
    public ContentNegotiatingViewResolver viewResolver() {
        ContentNegotiatingViewResolver contentNegotiatingViewResolver = new ContentNegotiatingViewResolver();
        contentNegotiatingViewResolver.setOrder(1);
        contentNegotiatingViewResolver.setFavorPathExtension(true);
        contentNegotiatingViewResolver.setFavorParameter(true);
        contentNegotiatingViewResolver.setIgnoreAcceptHeader(false);
        Map<String, String> mediaTypes = new HashMap<String, String>();
        mediaTypes.put("json", "application/x-json");
        mediaTypes.put("json", "text/json");
        mediaTypes.put("json", "text/x-json");
        mediaTypes.put("json", "application/json");
        mediaTypes.put("xml", "text/xml");
        mediaTypes.put("xml", "application/xml");
        contentNegotiatingViewResolver.setMediaTypes(mediaTypes);
        List<View> defaultViews = new ArrayList<View>();
        defaultViews.add(xmlView());
        defaultViews.add(jsonView());
        contentNegotiatingViewResolver.setDefaultViews(defaultViews);
        return contentNegotiatingViewResolver;
    }

    @Bean(name = "xStreamMarshaller")
    public XStreamMarshaller xStreamMarshaller() {
        return new XStreamMarshaller();
    }

    @Bean(name = "xmlView")
    public MarshallingView xmlView() {
        MarshallingView marshallingView = new MarshallingView(xStreamMarshaller());
        marshallingView.setContentType("application/xml");
        return marshallingView;
    }

    @Bean(name = "jsonView")
    public MappingJacksonJsonView jsonView() {
        MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
        mappingJacksonJsonView.setContentType("application/json");
        return mappingJacksonJsonView;
    }
}

还有我的控制器:

@Controller
@RequestMapping(value = { "/things" })
public class ThingController {

    @Autowired
    private ThingRepository thingRepository;

    @RequestMapping(value = { "/show/{thingId}" }, method = RequestMethod.GET)
    public String show(@PathVariable ObjectId thingId, Model model) {
        model.addAttribute("thing", thingRepository.findOne(thingId));
        return "things/show";
    }
}

【问题讨论】:

    标签: java json spring mongodb jackson


    【解决方案1】:

    默认情况下,Jackson 提供接收到的对象的序列化。 ObjectId 返回 Object,因此其属性在转换为 JSON 后可见。您需要指定所需的序列化类型,这里是字符串。用于创建 ThingRepository 的 Thing 实体类将如下所示:

    public class Thing {
        @Id
        @JsonSerialize(using= ToStringSerializer.class)
        ObjectId id;
    
        String name;
    }
    

    这里记下添加的注释@JsonSerialize(using= ToStringSerializer.class),它指示将 ObjectID 序列化为 String。

    【讨论】:

    • 如果你在 Kotlin 工作,那一定是@JsonSerialize(using = ToStringSerializer::class)
    • 我使用的是 Java 8。
    【解决方案2】:

    我只需要让 getId() 方法返回一个字符串。这是让 Jackson 停止序列化 ObjectId 的唯一方法。

    public String getId() {
        if (id != null) {
            return id.toString();
        } else {
            return null;
        }
    }
    
    public void setId(ObjectId id) {
        this.id = id;
    }
    

    setId() 仍然必须是 ObjectId,这样 Mongo(及其驱动程序)才能正确设置 ID。

    【讨论】:

      【解决方案3】:

      以前的答案起到了作用,但它很丑陋并且没有经过深思熟虑 - 一个明确的解决方法来实际解决问题。

      真正的问题是ObjectId 反序列化为它的组件部分。 MappingJacksonJsonView 看到 ObjectId 是什么,一个对象,然后开始处理它。在 JSON 中看到的反序列化字段是构成 ObjectId 的字段。要停止此类对象的序列化/反序列化,您必须配置一个扩展 ObjectMapper 的 CustomObjectMapper。

      这里是CustomeObjectMapper:

      public class CustomObjectMapper extends ObjectMapper {
      
          public CustomObjectMapper() {
              CustomSerializerFactory sf = new CustomSerializerFactory();
              sf.addSpecificMapping(ObjectId.class, new ObjectIdSerializer());
              this.setSerializerFactory(sf);
          }
      }
      

      这是CustomObjectMapper 使用的ObjectIdSerializer:

      public class ObjectIdSerializer extends SerializerBase<ObjectId> {
      
          protected ObjectIdSerializer(Class<ObjectId> t) {
              super(t);
          }
      
          public ObjectIdSerializer() {
              this(ObjectId.class);
          }
      
          @Override
          public void serialize(ObjectId value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
              jgen.writeString(value.toString());
          }
      }
      

      以下是您的 @Configuration-annotated 类中需要更改的内容:

      @Bean(name = "jsonView")
      public MappingJacksonJsonView jsonView() {
          final MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
          mappingJacksonJsonView.setContentType("application/json");
          mappingJacksonJsonView.setObjectMapper(new CustomObjectMapper());
          return mappingJacksonJsonView;
      }
      

      您基本上是在告诉杰克逊如何序列化/反序列化这个特定对象。像魅力一样工作。

      【讨论】:

      • 不需要自定义序列化程序。只需 ToStringSerializer 即可。
      【解决方案4】:

      如果您在 Spring Boot 中使用自动配置映射器的自动装配实例,则只需添加此自定义程序 bean:

      @Bean
      public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
          return builder -> builder.serializerByType(ObjectId.class, ToStringSerializer.instance);
      }
      

      相关进口:

      import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
      import org.bson.types.ObjectId;
      import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
      

      然后这将反映使用自动连线映射器的任何地方,例如:

      @Service
      public class MyService {
          private final ObjectMapper objectMapper;
          private final MongoTemplate mongoTemplate;
      
          @Autowired
          public MyService(ObjectMapper objectMapper) {
              this.objectMapper = objectMapper;
          }
      
          public String getJsonForMongoCommand(Document document) {
              return objectMapper.writeValueAsString(mongoTemplate.executeCommand(document));
          }
      }
      

      或者在这种特定情况下(未经测试,可能没有必要):

      @Bean(name = "jsonView")
      public MappingJacksonJsonView jsonView(ObjectMapper objectMapper) {
          final MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
          mappingJacksonJsonView.setContentType("application/json");
          mappingJacksonJsonView.setObjectMapper(objectMapper);
          return mappingJacksonJsonView;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-24
        • 2015-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多