【问题标题】:Can't make GlassFish use my MessageBodyWriter in JAX-RS无法让 GlassFish 在 JAX-RS 中使用我的 MessageBodyWriter
【发布时间】:2014-08-27 13:49:11
【问题描述】:

我需要在 GlassFish 4.0 中自定义 JAX-RS 的 JSON 输出。自定义 MessageBodyWriter 似乎很合适。我的问题是我不能举任何例子,例如http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html,由服务器调用。我只是设置断点以查看它是否被命中。我知道它在正确的包中,等等,因为我也尝试了自定义 WriterInterceptor 并且那个被击中就好了。我只需要将 @Provider 放在正确包中的 WriterInterceptor 上即可。

到目前为止我尝试过的事情:

  1. 只需使用@Provider
  2. 修改 web.xml 并使用自定义应用程序注册自定义 MOXyJsonProvider。应用程序类被调用,但 MessageBodyWriter/MOXyJsonProvider 未被调用。
  3. 添加 META-INF/services/javax.ws.rs.ext.MessageBodyWriter 文件,其中包含类名

代码如下:

@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class WebVisualizationJsonWriter extends MOXyJsonProvider {

@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return WebVisualizationJsonPayload.class == type
            || WebVisualizationJsonPayload.class == getDomainClass(genericType);
}

@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return isReadable(type, genericType, annotations, mediaType);
}

@Override
protected void preReadFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, String> httpHeaders, Unmarshaller unmarshaller) throws JAXBException {
    unmarshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, "$");
}

@Override
protected void preWriteTo(Object object, Class<?> type, Type genericType, Annotation[] annotations,
        MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, Marshaller marshaller)
        throws JAXBException {
    marshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, "$");
}
}

在 RESTful 服务调用期间,上述方法均未命中。

【问题讨论】:

  • 从调试中得出的结论是,问题在于,根据jersey.java.net/documentation/latest/…描述的算法,Jersey的ConfigurableMoxyJsonProvider总是会被优先选择,除非你写了MessageBodyWriter/@987654326使用比Object 更具体的类型参数化的@。但是如果你这样做,你就不能再扩展 MOXy 的 MOXyJsonProvider 了,因为它实现了 MessageBodyWriter.
  • 对我来说,设计缺陷似乎是ConfigurableMoxyJsonProvider 有效地使您列出的四种方法无法自定义。应该有办法用自定义子类替换ConfigurableMoxyJsonProvider 的默认注册实例。

标签: json rest glassfish jax-rs jersey-2.0


【解决方案1】:

要解决这个问题,必须先禁用 MOXy,然后再启用 CustomMoxyJsonProvider。

例子:

  1. 创建您自己的扩展 javax.ws.rs.core.Feature 的功能:

    @Provider
    public class CustomMoxyFeature implements Feature {
        @Override
        public boolean configure(final FeatureContext context) {
            final String disableMoxy = CommonProperties.MOXY_JSON_FEATURE_DISABLE + '.' + context.getConfiguration().getRuntimeType().name().toLowerCase();
            context.property(disableMoxy, true);
           return true;
        }
    }
    
  2. 创建您自己的扩展 MOXyJsonProvider 的提供程序:

    @Provider
    public class CustomMoxyJsonProvider extends MOXyJsonProvider {
        @Override
        public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return WebVisualizationJsonPayload.class == type
        || WebVisualizationJsonPayload.class == getDomainClass(genericType);
    }
    
        @Override
        public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return isReadable(type, genericType, annotations, mediaType);
    

    }

        @Override
        protected void preReadFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
    MultivaluedMap<String, String> httpHeaders, Unmarshaller unmarshaller) throws JAXBException {
            unmarshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, "$");
        }
    
        @Override
        protected void preWriteTo(Object object, Class<?> type, Type genericType, Annotation[] annotations,
    MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, Marshaller marshaller)
    throws JAXBException {
            marshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, "$");
        }
    }
    
  3. 在应用程序配置中添加此资源:

    @javax.ws.rs.ApplicationPath("webresources")
    public class ApplicationConfig extends Application {
    
        @Override
        public Set<Class<?>> getClasses() {
            Set<Class<?>> resources = new java.util.HashSet<>();
            addRestResourceClasses(resources);
            return resources;
        }
    
        private void addRestResourceClasses(Set<Class<?>> resources) {
            resources.add(com.vinichenkosa.moxyproblem.TestResource.class);
            resources.add(com.vinichenkosa.moxyproblem.custom_provider.CustomMoxyFeature.class);
            resources.add(com.vinichenkosa.moxyproblem.custom_provider.CustomMoxyJsonProvider.class);
        }
    }
    

【讨论】:

  • 禁用 MoxyJsonFeature 的属性名称已更改为 Jersey 2.10.4 的路径,该版本随 GlassFish 4.1 提供。现在不是jersey.config.disableMoxyJson.server,而是jersey.config.server.disableMoxyJson (!),参见。 Javadoc。所以最好把第1点的代码替换成这样:context.property( ServerProperties.MOXY_JSON_FEATURE_DISABLE, true );
【解决方案2】:

自从我们升级到 Glassfish 4.1 后,我也面临同样的问题。我们还升级了我们的 jersey 和 jax-rs 依赖项(如下所列)。下面是我们的自定义 MessageBodyWriter,它在编写对流

 @Provider
@Produces({"application/xml", "application/vnd.jenzabar.jx-json"})
public class RestDataSourceMessageBodyWriter implements MessageBodyWriter<Object> {

  // TODO pattern is probably too simple now, was "/paged/(^[/?]+)" 
    // and didn't work with expected URL, example "/DonationGroup/findAllGroupOriginTypes/paged/0,50"
  private static final Pattern pathPattern = Pattern.compile("/paged/(.*)");

  private static final Map<Class<?>, Class<?>[]> classMap;

  private static final ReadWriteLock classMapLock;

  static {
    classMap = new HashMap<Class<?>, Class<?>[]>();
    classMapLock = new ReentrantReadWriteLock();
  }


  /*
   * Instance fields.
   */


  @Context
  private volatile ServletContext servletContext;

  @Context
  private volatile HttpServletRequest request;

  @Context
  volatile Providers providers;

  @Context
  private volatile UriInfo uriInfo;

  protected volatile Logger logger;


  /*
   * Constructors.
   */


  public RestDataSourceMessageBodyWriter() {
    super();
    this.logger = this.createLogger();
    if (this.logger == null) {
      this.logger = this.defaultCreateLogger();
    }
    assert this.logger != null;
    if (this.logger.isLoggable(Level.FINER)) {
      this.logger.log(Level.FINER, "created", this);
    }
  }


  /*
   * Instance methods.
   */


  protected Logger createLogger() {
    return this.defaultCreateLogger();
  }

  private final Logger defaultCreateLogger() {
    Class<?> c = this.getClass();
    assert c != null;
    final String className = c.getName();
    String bundleName = null;
    Logger logger = Logger.getLogger(className);
    assert logger != null;
    if (logger.isLoggable(Level.FINER)) {
      logger.entering(className, "defaultCreateLogger");
    }
    while (c != null && bundleName == null) {
      bundleName = String.format("%sLogMessages", c.getName());
      if (logger.isLoggable(Level.FINEST)) {
        logger.logp(Level.FINEST, className, "defaultCreateLogger", "Looking for a ResourceBundle with the following bundle name: {0}", bundleName);
      }
      ResourceBundle rb = null;
      try {
        rb = ResourceBundle.getBundle(bundleName);        
      } catch (final MissingResourceException noBundle) {
        if (logger.isLoggable(Level.FINEST)) {
          logger.logp(Level.FINEST, className, "defaultCreateLogger", "No ResourceBundle found for name " + bundleName, noBundle);
        }
        bundleName = null;
        rb = null;
      }
      c = c.getSuperclass();
    }
    if (bundleName != null) {
      logger = Logger.getLogger(className, bundleName);
      assert logger != null;
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logp(Level.CONFIG, className, "defaultCreateLogger", "usingBundleName", bundleName);
      }
    }
    if (logger.isLoggable(Level.FINER)) {
      logger.exiting(className, "defaultCreateLogger", logger);
    }
    return logger;
  }

  @Override
  public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
      if (this.logger.isLoggable(Level.FINER)) {
          this.logger.entering(this.getClass().getName(), "isWriteable", new Object[] { type, genericType, annotations, mediaType });
      }
      boolean returnValue = false;
      if (type != null && !RestDataSourceResponse.class.isAssignableFrom(type)) {

          if (annotations != null && annotations.length > 0) {
              for (final Annotation a : annotations) {
                  if (a instanceof Decorate) {
                      final DecorationType decorationType = ((Decorate)a).value();
                      if (decorationType != null && decorationType.equals(DecorationType.NONE)) {
                          if (this.logger.isLoggable(Level.FINER)) {
                              this.logger.exiting(this.getClass().getName(), "isWriteable", Boolean.FALSE);
                          }
                          return false;
                      }
                  }
              }
          }

          MediaType modifiedMediaType = null;
          if (mediaType.toString().equals("application/vnd.jenzabar.jx-json")) {
              modifiedMediaType = MediaType.APPLICATION_JSON_TYPE;
          } else {
              modifiedMediaType = mediaType;
          }
          final MessageBodyWriter<RestDataSourceResponse> delegate = this.providers.getMessageBodyWriter(RestDataSourceResponse.class, RestDataSourceResponse.class, annotations, modifiedMediaType);
          if (this.logger.isLoggable(Level.FINE)) {
              this.logger.logp(Level.FINE, this.getClass().getName(), "isWriteable", "usingDelegate", delegate);
          }
          returnValue = delegate != null && delegate.isWriteable(RestDataSourceResponse.class, RestDataSourceResponse.class, annotations, modifiedMediaType);
      }
      if (this.logger.isLoggable(Level.FINER)) {
          this.logger.exiting(this.getClass().getName(), "isWriteable", Boolean.valueOf(returnValue));
      }
      return returnValue;
  }

【讨论】:

    猜你喜欢
    • 2018-07-24
    • 1970-01-01
    • 2014-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 2013-03-31
    相关资源
    最近更新 更多