Java Jersey ContextResolver GetContext()只调用一次

Java Jersey ContextResolver GetContext()只调用一次,java,jersey,jackson,jax-rs,Java,Jersey,Jackson,Jax Rs,我有以下ContextResolver实现,它基于查询参数应该返回相应的JSON映射器(pretty/DateToUtc/Both): 但是,getContext()函数在整个服务器生命周期内只调用一次,仅在第一次请求时调用。这个类的全部思想是在运行时根据url参数确定什么是映射器 更新 对每个uri路径调用一次getContext()。例如,将为/path1的所有请求生成漂亮的输出,而不考虑将来的漂亮queryParam。对path2的调用将再次调用getContext,但不会调用未来的pat

我有以下
ContextResolver
实现,它基于查询参数应该返回相应的JSON映射器(pretty/DateToUtc/Both):

但是,
getContext()
函数在整个服务器生命周期内只调用一次,仅在第一次请求时调用。这个类的全部思想是在运行时根据url参数确定什么是映射器

更新

对每个uri路径调用一次
getContext()。例如,将为/path1的所有请求生成漂亮的输出,而不考虑将来的漂亮
queryParam
。对path2的调用将再次调用getContext,但不会调用未来的path2调用

更新2

嗯,似乎每个类都会调用一次
GetContext
,并为特定类缓存它。这就是为什么它需要一个类作为参数。看来@LouisF是对的,objectMapper不适合条件序列化。但是,
ContainerResponseFilter
替代方案正在部分工作,但没有公开ObjectMapper功能,例如将日期转换为UTC。所以我现在很困惑什么是条件序列化的最合适的解决方案

已解决

在@LoisF的帮助下,我使用
ContainerResponseFilter
实现了条件序列化。我没有使用
ContextResolver
。以下是工作示例:

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.jaxrs.cfg.EndpointConfigBase;
import com.fasterxml.jackson.jaxrs.cfg.ObjectWriterInjector;
import com.fasterxml.jackson.jaxrs.cfg.ObjectWriterModifier;

/**
 * Created by matt on 17/01/2016.
 */
@Provider
public class ResultTransformer implements ContainerResponseFilter {


    public static final String OUTPUT_FORMAT_HEADER = "X-Output-Format";
    public static final ObjectMapper MAPPER         = new ObjectMapper();

    public static class OutputFormat {
        Boolean pretty              = true;
        Boolean dateAsTimestamp     = false;

        public Boolean getPretty() {
            return pretty;
        }

        public void setPretty(Boolean pretty) {
            this.pretty = pretty;
        }

        @JsonProperty("date_as_timestamp")
        public Boolean getDateAsTimestamp() {
            return dateAsTimestamp;
        }

        public void setDateAsTimestamp(Boolean dateAsTimestamp) {
            this.dateAsTimestamp = dateAsTimestamp;
        }
    }

    @Override
    public void filter(ContainerRequestContext reqCtx, ContainerResponseContext respCtx) throws IOException {

        String outputFormatStr = reqCtx.getHeaderString(OUTPUT_FORMAT_HEADER);
        OutputFormat outputFormat;
        if (outputFormatStr == null) {
            outputFormat = new OutputFormat();
        } else {
            try {
                outputFormat = MAPPER.readValue(outputFormatStr, OutputFormat.class);
                ObjectWriterInjector.set(new IndentingModifier(outputFormat));
            } catch (Exception e) {
                e.printStackTrace();
                ObjectWriterInjector.set(new IndentingModifier(new OutputFormat()));
            }
        }
    }

    public static class IndentingModifier extends ObjectWriterModifier {

       private OutputFormat outputFormat;

        public IndentingModifier(OutputFormat outputFormat) {
            this.outputFormat = outputFormat;

        }


        @Override
        public ObjectWriter modify(EndpointConfigBase<?> endpointConfigBase, MultivaluedMap<String, Object> multivaluedMap, Object o, ObjectWriter objectWriter, JsonGenerator jsonGenerator) throws IOException {
            if(outputFormat.getPretty())      jsonGenerator.useDefaultPrettyPrinter();
            if (outputFormat.dateAsTimestamp)  {
                objectWriter = objectWriter.with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            } else {
                objectWriter = objectWriter.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            }
            return objectWriter;
        }
    }

}
import java.io.IOException;
导入javax.ws.rs.container.ContainerRequestContext;
导入javax.ws.rs.container.ContainerResponseContext;
导入javax.ws.rs.container.ContainerResponseFilter;
导入javax.ws.rs.core.MultivaluedMap;
导入javax.ws.rs.ext.Provider;
导入com.fasterxml.jackson.annotation.JsonProperty;
导入com.fasterxml.jackson.core.JsonGenerator;
导入com.fasterxml.jackson.databind.ObjectMapper;
导入com.fasterxml.jackson.databind.ObjectWriter;
导入com.fasterxml.jackson.databind.SerializationFeature;
导入com.fasterxml.jackson.jaxrs.cfg.EndpointConfigBase;
导入com.fasterxml.jackson.jaxrs.cfg.ObjectWriterInjector;
导入com.fasterxml.jackson.jaxrs.cfg.ObjectWriterModifier;
/**
*马特于2016年1月17日创作。
*/
@提供者
公共类ResultTransformer实现ContainerResponseFilter{
公共静态最终字符串输出\u格式\u HEADER=“X-OUTPUT-FORMAT”;
public static final ObjectMapper MAPPER=new ObjectMapper();
公共静态类OutputFormat{
布尔值=真;
布尔dateAsTimestamp=false;
公共布尔getPretty(){
回归美丽;
}
公共void setPretty(布尔型pretty){
this.pretty=pretty;
}
@JsonProperty(“日期作为时间戳”)
公共布尔getDateAsTimestamp(){
返回日期:平均时间;
}
public void setDateAsTimestamp(布尔型dateAsTimestamp){
this.dateAsTimestamp=dateAsTimestamp;
}
}
@凌驾
公共无效筛选器(ContainerRequestContext reqCtx、ContainerResponseContext respCtx)引发IOException{
字符串outputFormatStr=reqCtx.getHeaderString(输出格式头);
输出格式输出格式;
if(outputFormatStr==null){
outputFormat=新的outputFormat();
}否则{
试一试{
outputFormat=MAPPER.readValue(outputFormatStr,outputFormat.class);
set(新的缩进修饰符(outputFormat));
}捕获(例外e){
e、 printStackTrace();
set(新的缩进修饰符(new OutputFormat());
}
}
}
公共静态类IndentingModifier扩展ObjectWriterModifier{
私有输出格式输出格式;
公共缩进修改器(OutputFormat OutputFormat){
this.outputFormat=outputFormat;
}
@凌驾
公共ObjectWriter修改(EndpointConfigBase EndpointConfigBase、MultivaluedMap MultivaluedMap、Object o、ObjectWriter ObjectWriter、JsonGenerator JsonGenerator)引发IOException{
if(outputFormat.getPretty())jsonGenerator.useDefaultPrettyPrinter();
if(outputFormat.dateAsTimestamp){
objectWriter=objectWriter.with(SerializationFeature.WRITE_DATES_作为_时间戳);
}否则{
objectWriter=objectWriter.without(SerializationFeature.WRITE_DATES_作为_时间戳);
}
返回objectWriter;
}
}
}

如果您希望通过请求获得它,则需要对每次呼叫进行评估。我在此建议将此逻辑移动到专用组件中,并执行以下操作:

@GET
public Response demo(@Context final UriInfo uriInfoContext, final String requestBody) {
    final ObjectMapper objectMapper = objectMapperResolver.resolve(uriInfoContext.getQueryParameters());
    objectMapper.readValue(requestBody, MyClass.class);
    ...
}

其中ObjtMpPraceRever根据查询参数

封装了选择正确对象映射器的逻辑,您应该考虑性能。 使用您的解决方案,您将为每个请求创建一个新的ObjectMapper实例。这个相当重!!!我发现ObjectMapper创建是JProfile测量期间的主要性能阻碍


关于线程安全性,不确定仅仅有两个静态成员用于pretty/non-pretty是否是一个足够的解决方案。为了缓存ObjectMapper,您需要注意JAX-RS框架使用的机制,以避免产生任何副作用。

因此,您想为每个请求确定要使用哪个映射器?这是一个微不足道的解决方案,不可扩展。添加漂亮过滤器的功能应该应用于基于
queryParams
的所有请求。在每个请求中添加建议的逻辑并不是一个好的软件设计。ContextResolver应该解决这个问题<代码>getContext()
应按设计调用每个请求。我发布的示例代码基于官方文档,因此
import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.jaxrs.cfg.EndpointConfigBase;
import com.fasterxml.jackson.jaxrs.cfg.ObjectWriterInjector;
import com.fasterxml.jackson.jaxrs.cfg.ObjectWriterModifier;

/**
 * Created by matt on 17/01/2016.
 */
@Provider
public class ResultTransformer implements ContainerResponseFilter {


    public static final String OUTPUT_FORMAT_HEADER = "X-Output-Format";
    public static final ObjectMapper MAPPER         = new ObjectMapper();

    public static class OutputFormat {
        Boolean pretty              = true;
        Boolean dateAsTimestamp     = false;

        public Boolean getPretty() {
            return pretty;
        }

        public void setPretty(Boolean pretty) {
            this.pretty = pretty;
        }

        @JsonProperty("date_as_timestamp")
        public Boolean getDateAsTimestamp() {
            return dateAsTimestamp;
        }

        public void setDateAsTimestamp(Boolean dateAsTimestamp) {
            this.dateAsTimestamp = dateAsTimestamp;
        }
    }

    @Override
    public void filter(ContainerRequestContext reqCtx, ContainerResponseContext respCtx) throws IOException {

        String outputFormatStr = reqCtx.getHeaderString(OUTPUT_FORMAT_HEADER);
        OutputFormat outputFormat;
        if (outputFormatStr == null) {
            outputFormat = new OutputFormat();
        } else {
            try {
                outputFormat = MAPPER.readValue(outputFormatStr, OutputFormat.class);
                ObjectWriterInjector.set(new IndentingModifier(outputFormat));
            } catch (Exception e) {
                e.printStackTrace();
                ObjectWriterInjector.set(new IndentingModifier(new OutputFormat()));
            }
        }
    }

    public static class IndentingModifier extends ObjectWriterModifier {

       private OutputFormat outputFormat;

        public IndentingModifier(OutputFormat outputFormat) {
            this.outputFormat = outputFormat;

        }


        @Override
        public ObjectWriter modify(EndpointConfigBase<?> endpointConfigBase, MultivaluedMap<String, Object> multivaluedMap, Object o, ObjectWriter objectWriter, JsonGenerator jsonGenerator) throws IOException {
            if(outputFormat.getPretty())      jsonGenerator.useDefaultPrettyPrinter();
            if (outputFormat.dateAsTimestamp)  {
                objectWriter = objectWriter.with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            } else {
                objectWriter = objectWriter.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            }
            return objectWriter;
        }
    }

}
@GET
public Response demo(@Context final UriInfo uriInfoContext, final String requestBody) {
    final ObjectMapper objectMapper = objectMapperResolver.resolve(uriInfoContext.getQueryParameters());
    objectMapper.readValue(requestBody, MyClass.class);
    ...
}