2

我有一个使用自定义 GSON JSON 适配器在 Payara 4 上运行的应用程序。我想迁移到 Payara 5 (5.191) 并开始使用 JSON-B。在我们当前的应用程序中,我们可以使用资源上的注释来控制 JSON 输出。

例如使用@Summarize

@GET
@Path("summary/{encryptedId}")
@Produces(MediaType.APPLICATION_JSON)
@Summarize
public Address findSummarized(@PathParam("encryptedId") String encryptedId) {
  return super.find(encryptedId);
}

这将导致在我们的 : 中使用不同的 GSON 配置@Provider

@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class GsonProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {

  public GsonProvider() {
    gson = getGson(EntityAdapter.class);
    gsonSummary = getGson(EntitySummaryAdapter.class);
  }

  ...

  @Override
  public void writeTo(T object,
                      Class<?> type,
                      Type genericType,
                      Annotation[] annotations,
                      MediaType mediaType,
                      MultivaluedMap<String, Object> httpHeaders,
                      OutputStream entityStream)
  throws IOException, WebApplicationException {
    boolean summarize = contains(annotations, Summarize.class);
    try (PrintWriter printWriter = new PrintWriter(entityStream)) {
      printWriter.write((summarize ? gsonSummary : gson).toJson(object));
      printWriter.flush();
    }
  }

}

我想在新的 JSON-B 设置中做类似的事情。我用 注释了我们的实体@JsonbTypeSerializer(MySerializer.class),所以我希望能够从序列化程序中检测它应该做什么:要么创建一个完整的序列化 JSON 对象,要么创建一个摘要。

我希望做的是在 中设置一个属性JsonbConfig,如下所示:

JsonbConfig config = new JsonbConfig()
        .setProperty("com.myCompany.jsonb.summarize", true);

@Context并使用(只是猜测这可能在这里工作)在序列化程序中读取它,如下所示:

@Context
private JsonbConfiguration config;

..但事实并非如此。有什么方法可以从一个访问 JAX-RS 资源注释JsonbSerializer

4

2 回答 2

0

Jsonb您可以使用JAX-RS 提供程序类中的两个单独实例来实现类似的目标,如下所示:

@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class JsonbProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {

  private static final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
                                       .withAdapters(new EntityAdapter()));
  private static final Jsonb jsonbSummary = JsonbBuilder.create(new JsonbConfig()
                                       .withAdapters(new EntitySummaryAdapter()));

  ...

  @Override
  public void writeTo(T object,
                      Class<?> type,
                      Type genericType,
                      Annotation[] annotations,
                      MediaType mediaType,
                      MultivaluedMap<String, Object> httpHeaders,
                      OutputStream entityStream)
  throws IOException, WebApplicationException {
    boolean summarize = contains(annotations, Summarize.class);
    try (PrintWriter printWriter = new PrintWriter(entityStream)) {
      printWriter.write((summarize ? jsonbSummary : jsonb).toJson(object));
      printWriter.flush();
    }
  }

}
于 2019-12-21T16:15:35.320 回答
0

最后,我选择从我的实体中创建摘要并将注释放在我的 REST 资源上。这是一些工作,但我认为这是值得的。

我创建了一个Summarizable界面并在其中添加了一个默认方法,以基于PropertyVisibilityStrategy我们为实体的完整版本创建的扩展版本创建任何实体的简单地图摘要。

public interface Summarizable {

  public default Map<String, Object> toSummary() {
    SummaryPropertyVisibilityStrategy summaryStrategy = new SummaryPropertyVisibilityStrategy();
    Map<String, Object> summary = new LinkedHashMap<>();
    ReflectionUtils.getFields(this.getClass())
            .stream()
            .filter(summaryStrategy::isVisible)
            .map(f -> new AbstractMap.SimpleEntry<>(f.getName(), summarize(f)))
            .filter(e -> e.getValue() != null)
            .forEach(e -> summary.put(e.getKey(), e.getValue()));
    return summary;
  }

  public default Object summarize(final Field field) {
    Object value = ReflectionUtils.getValueJsonb(this, field);
    return value != null && Stream.of(ManyToOne.class, OneToOne.class).anyMatch(field::isAnnotationPresent)
                   ? value.toString()
                   : value;
  }

}
  public static Object getValueJsonb(final Object object, final Field field) {
    field.setAccessible(true);
    JsonbTypeAdapter adapterAnnotation = field.getAnnotation(JsonbTypeAdapter.class);
    try {
      Object value = field.get(object);
      return adapterAnnotation == null
             ? value
             : adapterAnnotation.value().newInstance().adaptToJson(value);
    }
    catch (Exception ex) {
      throw new IllegalStateException(ex);
    }
  }
于 2020-01-15T08:17:15.627 回答