【问题标题】:Handle JSON serialization in Jboss EAP 7.2.0.GA在 Jboss EAP 7.2.0.GA 中处理 JSON 序列化
【发布时间】:2020-01-05 16:00:25
【问题描述】:

在我的 Jboss 中,我尝试使用 JAX-RS 实现 REST 服务。它应该返回某个对象的 JSON 序列化版本

 @GET
  @Produces({ MediaType.APPLICATION_JSON })
  public BlacklistDTO getByName(
      @QueryParam("gav") final List<String> gavStringList)
  {
     ...
  }

对象的某些部分未正确序列化(结果为空)。如何处理/自定义 Jboss 生成 JSON 的方式?

【问题讨论】:

  • 嗨,您的应用程序使用 CDI 吗?你使用杰克逊转换为 JSON 吗?你用 Resteasy 吗?
  • 我怎么知道?我正在运行一个 Jboss,这可能配置在 somewhere 中,但不在我的代码或我的 pom.xml 中。
  • 通常你有一个 CDI 描述符,在 META-INF/beans.xml 或 WEB-INF/beans.xml 中的 beans.xml。这会在您的环境中激活 CDI。 Resteasy 是 Jboss/EAP 中 jax-rs 的默认实现,EAP v7.4.0 使用的是 Resteasy v3.5.0 (docs.jboss.org/resteasy/docs/3.5.0.Final/userguide/html_single)。检查您的 pom.xml 它将包括例如。一个 resteasy-jackson2-provider 或一个 resteasy-jettison-provider 来确定您使用的是什么 json 提供程序(或在调试模式下检查您的堆栈跟踪)
  • 您需要展示您的BlacklistDTO 的结构并展示您期望生成的 JSON 样本。目前我认为 CDI 与您的问题无关。
  • 抱歉回复晚了。我的 POM 只引用了javaee-api,我在项目中没有任何资源。我不知道 CDI、Jackson 还是 Resteasy 是否参与了这个过程,但很有趣。

标签: java json jboss jax-rs


【解决方案1】:

您可以自定义实用程序的配置以序列化/反序列化 JSON(通常是 EAP 中包含的 Jackson),并将模块配置/注册到 Jackson,以指示如何对复杂对象执行此工作。

如果您使用 CDI + Resteasy + Jackson,您可以这样做:

  1. 提供一个 JAX-RS 自定义 Json 提供程序,您可以在其中使用自定义配置配置您的 Jackson ObjectMapper。例如。

    @Provider
    @Produces(MediaType.APPLICATION_JSON)
    public class CustomJsonProvider implements ContextResolver<ObjectMapper> {
    private final ObjectMapper mapper;
    
    public CustomJsonProvider() {
        ObjectMapper mapperCdi = null;
        //if you are using CDI and you have your own Custom Object Mapper...
        BeanManager bm = CDI.current().getBeanManager();
        Set<Bean<?>> sBeans = bm.getBeans(ObjectMapper.class);
        if (sBeans != null && !sBeans.isEmpty()) {
            @SuppressWarnings("unchecked")
            Bean<ObjectMapper> bean = (Bean<ObjectMapper>) sBeans.iterator().next();
            CreationalContext<ObjectMapper> ctx = bm.createCreationalContext(bean);
            mapperCdi = (ObjectMapper) bm.getReference(bean, ObjectMapper.class, ctx);
        }
        if (mapperCdi != null) {
            mapper = mapperCdi;
        }else {
        //if you are not using CDI, you can create your own Custom Object Mapper or get it from a factory e.g you can do here AppConfig.getObjectMapperInstance() or create a new one
            mapper = new ObjectMapper();
            //eg. configuration of Hibernate 5 - Jackson Module
            Hibernate5Module h5m = new Hibernate5Module();
            h5m.configure(Hibernate5Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
            mapper.registerModule((com.fasterxml.jackson.databind.Module) h5m);
    
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                    .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
            mapper.setSerializationInclusion(Include.NON_NULL);
    
            //eg. custom Jackson SimpleModule registration
            SimpleModule module = new SimpleModule("PaginationModule") {
                private static final long serialVersionUID = 1L;
    
                @Override
                public void setupModule(SetupContext context) {
                    context.addAbstractTypeResolver(
                            new SimpleAbstractTypeResolver().addMapping(Slice.class, SliceClientImpl.class));
                    context.addAbstractTypeResolver(
                            new SimpleAbstractTypeResolver().addMapping(Page.class, PageClientImpl.class));
                }
            };
            mapper.registerModule(module);
        }
    }
    
    @Override
    public ObjectMapper getContext(Class<?> objectType) {
        return mapper;
    }
    }
    
  2. 如果您使用 CDI,请定义您的“生产者”方法 (@Produce) 和 Jackson ObjectMapper 工厂:

    @ApplicationScoped
    public class AppConfig {
    private static ObjectMapper objectMapper;
    // Jackson Object Mapper
    @Produces
    public ObjectMapper createMapper() {
        return AppConfig.getObjectMapperInstance();
    }
    
    public static ObjectMapper getObjectMapperInstance() {
        if (objectMapper == null) {
            objectMapper = new ObjectMapper();
    
            //eg. configuration of Hibernate 5 - Jackson Module
            //Hibernate5Module h5m = new Hibernate5Module();
            //h5m.configure(Hibernate5Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
            //objectMapper.registerModule((com.fasterxml.jackson.databind.Module) h5m);
    
            //eg. configuration of Joda - Jackson Module
            objectMapper.registerModule(new JodaModule());
            objectMapper.setTimeZone(TimeZone.getDefault());
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                    .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            objectMapper.setSerializationInclusion(Include.NON_NULL);
    
            //eg. custom Jackson SimpleModule registration
            SimpleModule module = new SimpleModule("PaginationModule") {
                private static final long serialVersionUID = 1L;
                @Override
                public void setupModule(SetupContext context) {
                    context.addAbstractTypeResolver(
                            new SimpleAbstractTypeResolver().addMapping(Slice.class, SliceClientImpl.class));
                    context.addAbstractTypeResolver(
                            new SimpleAbstractTypeResolver().addMapping(Page.class, PageClientImpl.class));
                }
            };
            objectMapper.registerModule(module);
    
        }
        return objectMapper;
    }
    }
    
  3. 检查您的提供程序是否已由 Jax-rs / Resteasy 注册:

如果您的 jackson 配置未注册,请尝试在 web.xml 的上下文中添加以下行:

<context-param>

  <param-name>resteasy.providers</param-name>

  <param-value>your.package.CustomJsonProvider</param-value>

</context-param>

有时,需要配置为Service Provider,添加一个文件“META-INF/services/javax.ws.rs.ext.Providers”(或者在WEB-INF中根据你使用war的打包类型,耳朵、罐子等)与此内容:

your.package.CustomJsonProvider

以另一种方式,您可以返回一个 String(或一个 Response 对象),将您的 ObjectMapper(或处理 JSON 格式的实用程序)注入您的 Service 并创建/在 return 语句之前序列化您的对象。

例如。使用 Json-b

@Path("/myservice")
public class MyService {

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/resources")
    public Response createJson(@FormParam("name") String name, @FormParam("surname") String surname) {
        Response response;
        User u = new User(name, surname);
        Jsonb jsonb = JsonbBuilder.create();
        String jsonString = jsonb.toJson(u);
        response = Response.ok(jsonString).build();

        return response;
    }
}

例如。使用 json-b 以编程方式创建自定义 json

 // Create Json and serialize    
 JsonObject json = Json.createObjectBuilder()
 .add("name", "Falco")
 .add("age", BigDecimal.valueOf(3))
 .add("biteable", Boolean.FALSE).build();    String result = json.toString();

例如。使用 Jackson 以编程方式创建自定义 json

    ObjectMapper mapper = new ObjectMapper();
    ArrayNode arrayNode = mapper.createArrayNode();
    ObjectNode objectNode1 = mapper.createObjectNode();
    objectNode1.put("name", "Anna");
    objectNode1.put("surname", "T");
    arrayNode.add(objectNode1);
    ObjectNode objectNode2 = mapper.createObjectNode();
    objectNode2.put("name", "John");
    objectNode2.put("surname", "X");
    arrayNode.add(objectNode2);

    String json = arrayNode.toString();

希望对你有帮助。

【讨论】:

  • 非常感谢。不幸的是,我不知道我是否使用 CDI、Jackson 或 Resteasy 或其他任何东西。我没有 web.xml 或其他资源,并且除了 javaee-api 之外,我在 POM 中没有依赖项。
  • 你能提供你的 DTO 结构和对象坏序列化吗?您的 pom.xml 中是否导入了 bom?尝试在调试模式下使用断点发现您的 json 提供程序:github.com/resteasy/Resteasy/blob/…
  • 如果您知道您的 json 提供程序,您可以将其替换为您的自定义实现。您也可以在 DEBUG 中检查控制台/服务器日志以检查 resteasy、jackson 或 jettison。如果你不关心你当前的提供者,你可以按照步骤添加一个新的......它将覆盖你的默认实现。请注意在您的 pom 中将您的依赖项(提供程序、jackson、jettison 等)添加为“已提供”(access.redhat.com/documentation/en-us/…
  • 我的 DTO 问题是一个包含各种字段的对象。其中一个字段不是字符串,而是包含一个字符串字段本身。该字段被序列化为空 {}。我只是认为应该可以找出 Jboss 使用的标准,例如如果不提供任何配置会导致 Jackson 或 Gson 或其他。
猜你喜欢
  • 1970-01-01
  • 2020-06-04
  • 2018-03-27
  • 2019-11-02
  • 2015-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-12
相关资源
最近更新 更多