【问题标题】:Jackson ObjectMapper in Jersey has error with multi thread泽西岛的杰克逊 ObjectMapper 多线程出错
【发布时间】:2017-11-21 17:43:36
【问题描述】:

我有一个应用程序使用球衣 2,Jackson (jersey-media-json-jackson) 和 ObjectMapper。

线程同时访问同一个服务时,序列化失败,部分对象序列化为空,如{}。

例子:

{"order":1,"itens":[{"id":91},{"id":85},{"id":32},{"id":19},{"id":58},{"id":98},{"id":75},{"id":78},{"id":84},{"id":79}]} 
{"order":1,"itens":[{"id":77},{"id":9},{"id":83},{},{},{},{},{},{},{}]} -> bug
{"order":1,"itens":[{"id":71},{"id":94},{"id":58},{},{},{},{},{},{},{}]} -> bug
{"order":1,"itens":[{"id":4},{"id":4},{"id":73},{"id":48},{"id":57},{"id":47},{"id":60},{"id":22},{"id":44},{"id":48}]}

我的代码:

@provider
@Produces (MediaType.APPLICATION_JSON)
public class ObjectMapperResolverJ2 implements ContextResolver <ObjectMapper> {

    private final ObjectMapper mapper;

    public ObjectMapperResolverJ2 () {
        mapper = new ObjectMapper ();

        mapper.setSerializationInclusion (JsonInclude.Include.NON_NULL);

        mapper.enable (DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);

        mapper.enable (DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
        mapper.enable (DeserializationFeature.USE_BIG_INTEGER_FOR_INTS);

        mapper.disable (SerializationFeature.FAIL_ON_EMPTY_BEANS);

        mapper.disable (SerializationFeature.WRITE_EMPTY_JSON_ARRAYS);

        mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        mapper.configure (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY);
        mapper.setVisibility (PropertyAccessor.SETTER, Visibility.ANY);
        mapper.setVisibility (PropertyAccessor.GETTER, Visibility.ANY);
        mapper.setVisibility (PropertyAccessor.ALL, Visibility.ANY);
        mapper.getVisibilityChecker (). withFieldVisibility (Visibility.ANY);
        mapper.getVisibilityChecker (). withSetterVisibility (Visibility.ANY);
        mapper.getVisibilityChecker () .GetterVisibility (Visibility.ANY);
        mapper.getVisibilityChecker () .with (Visibility.ANY);

       
    }

    @Override
    public ObjectMapper getContext (Class <?> type) {
        return mapper;
    }

}

MyApplication.java

public class MyApplication extends ResourceConfig {

        public MyApplication () {

            register (JacksonFeature.class);
            register (ObjectMapperResolverJ2.class);
        }

    }

服务

@GET
    @Path ("/{Order}")
    @Produces (MediaType.APPLICATION_JSON)
    public OrderDTO getOrder (@PathParam("Order") Integer code) {
         // I change return to simplify
         OrderDTO order = new OrderDTO();
         order.setOrder(1);

         List<ItemDTO> itens = new ArrayList<>();

         for (int i = 0; i < 10; i++) {

            ItemDTO item = new ItemDTO();
            item.setId((int) (100 * Math.random()));
             itens.add(item);
         }

         order.setItens(itens);

         return order;
    }

球衣版本:2.21 杰克逊版本 2.5.1 雄猫 7.0.59

【问题讨论】:

  • @Path ("/ {Order}") 空格是故意的吗?
  • 你必须调试findOrder 看看为什么它会返回一些空项目。它看起来像一个错误......
  • @Path ("/{Order}") 复制源失败
  • @alfasin 我用 OrderDTO 的 toString 写了一个日志,日志没问题。
  • 然后使用嗅探器查看来自服务器的响应在客户端读取之前在客户端看起来不错。此外,假设问题确实在客户端,您只提供了在这种情况下不相关的服务器代码。

标签: java multithreading jackson jersey-2.0


【解决方案1】:

我在 Jersey 版本 2.0、Jackson 版本 1.9.11 和 Tomcat 7.0.59 上进行了测试,并且成功了。

【讨论】:

    【解决方案2】:

    我解决了这个问题,之前更改了 ObjectMapper 的注册方式

    register(ObjectMapperResolverJ2.class);
    

    之后:

    JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
    provider.setMapper(getObjectMapper());
    register(provider);
    

    MyApplication.java

    public class MyApplication extends ResourceConfig {
    
        public MyApplication () {
    
            register (JacksonFeature.class);
            //register(ObjectMapperResolverJ2.class); 
    
               JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
                provider.setMapper(getObjectMapper());
                register(provider);
        }
    
    
        private ObjectMapper  getObjectMapper(){
            ObjectMapper  mapper = new ObjectMapper ();
    
            mapper.setSerializationInclusion (JsonInclude.Include.NON_NULL);
    
            mapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
            mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
            mapper.enable(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS);
    
            mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    
            mapper.disable(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS);
    
            mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    
            mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    
            mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
            mapper.setVisibility(PropertyAccessor.SETTER, Visibility.ANY);
            mapper.setVisibility(PropertyAccessor.GETTER, Visibility.ANY);
            mapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
            mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY);
            mapper.getVisibilityChecker().withSetterVisibility(Visibility.ANY);
            mapper.getVisibilityChecker().GetterVisibility(Visibility.ANY);
            mapper.getVisibilityChecker().with (Visibility.ANY);
    
            return mapper;
    
        }
    
    
    }
    

    【讨论】:

      【解决方案3】:

      “解决”它的最简单方法是使用 ThreadLocal,因此每个线程将使用自己的副本

      private static final ThreadLocal<ObjectMapper> objectMapperThreadLocal = new ThreadLocal<>();
      
      public static ObjectMapper getObjectMapper() {
          ObjectMapper objectMapper = objectMapperThreadLocal.get();
          if (objectMapper == null) {
              objectMapper = new ObjectMapper();
              objectMapperThreadLocal.set(objectMapper);
          }
          return objectMapper;
      }
      

      【讨论】:

      • ObjectMapper 应该是线程安全的。这样的事情不应该是必要的,而且 OP 的实际问题很可能与对象映射器无关。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-15
      • 2015-10-19
      • 2012-06-07
      • 2015-02-07
      相关资源
      最近更新 更多