我需要在GlassFish 4.0中自定义JAX-RS的JSON输出。自定义MessageBodyWriter似乎很合适。我的问题是我无法做出任何例子,例如: http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html,由服务器调用。我只是设置断点以查看它是否被击中。我知道它在正确的包装中等等,因为我也尝试过自定义的WriterInterceptor,并且它被击中就好了。我只需将@Provider放在正确包装中的WriterInterceptor上即可。
到目前为止我尝试过的事情:
以下是代码:
@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服务调用期间,没有任何上述方法被命中。
答案 0 :(得分:3)
要解决此问题,必须禁用MOXy,然后启用CustomMoxyJsonProvider。
示例:
创建自己的功能,扩展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;
}
}
创建扩展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, "$");
}
}
在应用程序配置中添加此资源:
@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);
}
}
答案 1 :(得分:0)
自从我们升级到Glassfish 4.1后,我也遇到了同样的问题。我们还升级了我们的jersey和jax-rs依赖项(如下所示).Below是我们的自定义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;
}