我们正在使用IBM捆绑的Apache Wink为我们的应用程序提供JAXRS端点。我们正在编写Websphere 8.5.5。由于我们符合servlet 3.0,因此我们使用“编程”方式配置JaxRS应用程序,这意味着web.xml中没有条目,我们依赖于类扫描来注释jax rs资源。一般来说,它工作正常。
@ApplicationPath("/api/v1/")
public class MyApplication extends Application{
此版本的Websphere与Apache Wink一起使用Jackson 1.6.x进行JSON de / serialization,一般来说效果很好。我们希望改变Object Mapper的一些默认值
因此我们定义了一个客户上下文解析器,只需更改一些se / deserialzation属性。
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class CustomJackssonConverter implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public AibasJackssonConverter() {
defaultObjectMapper = createDefaultMapper();
}
...
mapper.getSerializationConfig().set(SerializationConfig.Feature.INDENT_OUTPUT, true);
在JAX-RS调用期间,我们可以看到容器注册了新的Provider,没有错误
问题在于,配置没有“跟随”,从日志中我可以看到Wink引擎正在查找WinkJacksonProvider,而WinkJacksonProvider反过来......返回遵循Jackson(s)默认值的JacksonProvider ?
有没有办法只更改此默认值?
我尝试更改此处所示的Application对象的实现,以便以编程方式配置Providers,但它不起作用。
http://www.ibm.com/developerworks/java/library/wa-aj-jackson/index.html
任何提示或提示?
非常感谢
答案 0 :(得分:3)
我通过实现MessageBodyWriter类解决了这个问题,如下所示:
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class DefaultMessageBodyWriter implements MessageBodyWriter<Object> {
@Override
public long getSize(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
mapper.writeValue(entityStream, object);
}
}
每次请求JSON序列化时,此类都会生效,最后会调用其writeTo方法。
这里按照WebSphere的要求关闭SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS。
答案 1 :(得分:1)
我找到了ContextResource的可行解决方案。
您需要Jackson的JAX-RS提供程序依赖项。 Maven示例:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.7</version>
</dependency>
接下来,您可以实现ContextResolver
@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
public JacksonConfig() {
objectMapper = createObjectMapper();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return objectMapper;
}
private ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
// some mapper configurations
return mapper;
}
}
最后,您必须在Application类中注册JacksonJaxbJsonProvider和ContextResolver。
public class RestApplicationConfig extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
resources.add(JacksonJaxbJsonProvider.class);
resources.add(JacksonConfig.class);
// Add other resources
return resources;
}
}
答案 2 :(得分:0)
我正在使用自由概要文件服务器20.0.0.0和eclipselink 2.7.6。缺省情况下,JAXRS使用eclipselink中的MoxyJsonProvider,并且抛出“检测到周期”错误。我想用我的ObjectMapper或Jackson Json Provider覆盖默认的JAXB Moxy提供程序。
public Set<Class<?>> getClasses()
无效。我必须创建另一个类文件来创建public class JaxbJsonProvider extends JacksonJaxbJsonProvider
并将其注释为@Provider。这个解决方案对我有用。
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
@Provider
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class JaxbJsonProvider extends JacksonJaxbJsonProvider {
}
另一个文件是
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Provider
public class JacksonObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public JacksonObjectMapperProvider() {
defaultObjectMapper = createDefaultMapper();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
public static ObjectMapper createDefaultMapper() {
log.info(String.format("Registering ObjectMapper modules"));
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.configure(MapperFeature.USE_GETTERS_AS_SETTERS, true);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return mapper;
}
}
重新启动自由配置文件服务器,REST API可以正常工作。请注意,@ Slf4j仅用于记录语句,并且可以跳过mapper config选项。 Liberty建议使用mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
。所有其他设置均取决于您的项目设置。
答案 3 :(得分:-1)
我在WAS v8.0.0.x中使用MOXy而不是Jackson。
要覆盖Jackson,我实现我的Application类:
@Named
@ApplicationScoped
@ApplicationPath("/resources/")
public class WinkApplication extends Application implements Serializable {
private static final long serialVersionUID = 1L;
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(WinkResource.class);
classes.add(WinkMOXyJsonProvider.class);
classes.add(WinkResponseException.class);
classes.add(WinkResponseExceptionMapper.class);
return classes;
}
}
但是,我注意到WAS似乎忽略了注释:
@ApplicationPath("/resources/")
所以,我已经使用了web.xml:
<!-- Wink Servlet -->
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.company.team.project.webservices.config.WinkApplication</param-value>
</init-param>
<!-- <init-param>
<param-name>propertiesLocation</param-name>
<param-value>/WEB-INF/my-wink-properties.properties</param-value>
</init-param> -->
<load-on-startup>1</load-on-startup>
<enabled>true</enabled>
<async-supported>false</async-supported>
</servlet>
<!-- Wink Servlet Mapping -->
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
关键是,由于WAS或Wink在使用ApplicationPath注释时似乎忽略了Application实现,Wink会加载默认的Application类,默认情况下使用Jackson。
是的,我已阅读文档,甚至在线观看IBM视频,提到@ApplicationPath允许您避免XML配置,但这个问题似乎是个错误。
更新:
另一种方法可能是David Blevins在另一篇SO帖子中提到的。