如何禁用Jersey的JacksonJsonProvider自动注册,以便我自己使用?

时间:2014-05-03 06:29:45

标签: java json jersey jersey-2.0

我有@GET方法,注明了@Produces( MediaType.APPLICATION_JSON )。我想在Jersey中禁用JSON处理时看到该调用失败,但无论我做什么,当我在浏览器中访问该URL方法时,它继续生成JSON输出。

当我在com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider的构造函数中放置一个断点时,我发现在实例化MessageBodyFactory时它正在注册。特别是,在线下:

final Set<MessageBodyReader> mbrs = Providers.getProviders(locator, MessageBodyReader.class);

即使我禁用了所有自动发现,也会发现JacksonJsonProvider。因此,我无法注册我自己的提供自定义ObjectMapper。总是使用默认值。

方法如下:

@GET
@Produces( MediaType.APPLICATION_JSON )
public Status getStatus() {
    return new Status("test");   
}

在我的应用程序中,我做出了我认为合适(甚至是过度杀伤)的配置:

public class CustomResourceConfig extends ResourceConfig {

public CustomResourceConfig() {

property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
property(CommonProperties.JSON_PROCESSING_FEATURE_DISABLE, true);
property(CommonProperties.MOXY_JSON_FEATURE_DISABLE, true);

property(ServerProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
property(ServerProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
property(ServerProperties.MOXY_JSON_FEATURE_DISABLE, true);
property(ServerProperties.JSON_PROCESSING_FEATURE_DISABLE, true);

property(ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
property(ClientProperties.JSON_PROCESSING_FEATURE_DISABLE, true);

packages("test.package.api");
}
}

我在web.xml中放置了以下配置:

<servlet>  
    <servlet-name>jersey-servlet</servlet-name>  
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

    <init-param>
        <param-name>jersey.config.server.tracing</param-name>
        <param-value>ALL</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.disableMetainfServicesLookup</param-name>
        <param-value>1</param-value>
    </init-param>

    <init-param>
        <param-name>jersey.config.disableJsonProcessing</param-name>
        <param-value>1</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.disableMoxyJson</param-name>
        <param-value>1</param-value>
    </init-param>

    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.specktro.orchid.deployment.registry.CustomResourceConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>  
 </servlet>

我的pom.xml包含以下依赖项:

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
    </dependency>
    <dependency> 
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
    </dependency>

版本由父POM管理,但我需要使用Jackson 2.3.2,并且我使用Jersey 2.7(也尝试使用2.6,结果相同)。

我还尝试注册使用我的对象映射器的JacksonJaxbJsonProvider

register(new JacksonJaxbJsonProvider(objectMapper, null));

但是这会导致两个JacksonJsonProviders注册:一个用于JacksonJaxbJsonProvider,一个用于Jersey在初始化期间注册,一个被使用,因此我的注册被忽略。

如何让泽西岛使用我的JacksonJsonProvider代替默认值,以便我可以提供自己的ObjectMapper

更新 当然我也尝试创建一个自定义的ContextResolver,它提供了一个自定义的ObjectMapper并注册了它,但它被忽略了。

2 个答案:

答案 0 :(得分:0)

发现问题!! 我没有像通常人们那样返回一个物体。相反,我抛出了一个WebApplicationException的子类,它在客户端显示为JSON:

public class ApplicationException extends WebApplicationException {
    private static final long serialVersionUID = 1L;

    public ApplicationException(int errorCode, String message) {
        super(Response.status(Response.Status.OK).entity(
                    JsonNodeFactory.instance.objectNode()
                    .put("errorCode", errorCode)
                    .put("errorMessage", message).toString())
                .type(MediaType.APPLICATION_JSON).build());
    }

}

这是泽西岛的一个问题......当泽西岛处理这个异常时,它没有使用正确的Json Provider ...而是它注册了一个默认的没有我的自定义设置,也没有查询我有的ContextResolver注册导致一个未格式化的JSON(我在我的ObjectMapper上打开了漂亮的打印件)。

我在JIRA中打开了泽西岛的一个错误: https://java.net/jira/browse/JERSEY-2503

我希望这有助于另一个可怜的灵魂试图处理这个案子。

答案 1 :(得分:0)

看起来这样可行。我建立了一个我在JerseyConfig注册的nop JacksonJsonProvider。这是我用来制作nop JacksonJsonProvider的代码:

import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

public class NopJacksonProviderBuilder {

    public static JacksonJaxbJsonProvider nopJacksonJaxbJsonProvider(){
        JacksonJaxbJsonProvider result = new JacksonJaxbJsonProvider(new NopObjectMapper(), null);
        result.checkCanSerialize(true);
        result.checkCanDeserialize(true);
        return result;
    }

    public static JacksonJsonProvider nopJacksonJsonProvider(){
        JacksonJsonProvider result = new JacksonJsonProvider(new NopObjectMapper(), null);
        result.checkCanSerialize(true);
        result.checkCanDeserialize(true);
        return result;
    }

    @SuppressWarnings("serial")
    private static class NopObjectMapper extends ObjectMapper{

        @Override
        public boolean canDeserialize(JavaType type) {
            return false;
        }

        @Override
        public boolean canDeserialize(JavaType type, AtomicReference<Throwable> cause){
            return false;
        }

        @Override
        public boolean canSerialize(Class<?> type) {
            return false;
        }

        @Override
        public boolean canSerialize(Class<?> type, AtomicReference<Throwable> cause) {
            return false;
        }

   }
}