基于条件

时间:2015-08-05 08:25:31

标签: java jersey jackson mule

我正在使用Mule 3.5.2,我有一个发送和接收JSON消息的REST服务。该服务适用于挪威和瑞典。所有日期都以字符串形式发送,但瑞典和挪威的格式不同。我通过URL知道哪个国家/地区称我们的服务。我正在使用自定义日期序列化器和反序列化器。

接收JSON消息时我可以作弊,格式不同,在我的自定义反序列化器中我可以尝试一种格式。如果失败了我就试试另一个。但是:如何以正确的格式序列化?

似乎没有任何方法可以将参数发送到序列化程序,这个特定的消息发送到挪威,所以使用这种日期格式......然后下一个去瑞典使用其他格式等。

我所拥有的代码,可能有所帮助:

@GET
@Path("{country:se|no}/{id}")
public Response webservice(@PathParam("country") String country,
        @PathParam("id") String id) {
    country = country.toUpperCase();
    WebServiceResponse response = doWebServiceStuff(id, country)
    return Response.ok(reponse).build();
}

Response有一个.language()方法,但这似乎只会影响标题。

@JsonAutoDetect
public class WebServiceResponse {

    @JsonSerialize(using = JsonDateSerializer.class)
    @JsonDeserialize(using = JsonDateDeserializer.class)
    private Date date;

    public void setDate(Date d) { this.date = d; }
    public Date getDate() { return this.date; }
}
今天

Serializer。我希望能够适应挪威用户或瑞典用户。

public class JsonDateSerializer extends JsonSerializer<Date> {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

@Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException {
        String formattedDate = dateFormat.format(date);
        gen.writeString(formattedDate);
        provider.getConfig().getDateFormat()
    }
}

解串器。它有大致相同的问题,但我可以使用try / catch包围它...如果瑞典日期格式无效,请尝试使用挪威语编号进行解析,如果仍然存在问题则抛出RuntimeException。

public class JsonDateDeserializer extends JsonDeserializer<Date> {

    @Override
    public Date deserialize(JsonParser parser, DeserializationContext deserializationContext)
        throws IOException, JsonProcessingException {

        String dateText = parser.getText();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            return dateFormat.parse(dateText);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            throw new RuntimeException("Can't parse date " + dateText, e);
        }
    }

}

顺便说一句......我正在使用Jackson的codehaus版本,因为它似乎与Mule一起使用。我尝试了FasterXML版本,但是没有使用我的自定义序列化器,也没有使用新的基于注释的格式化程序(因此您不需要自定义序列化程序)。确切地说是版本1.9.11。

同样:问题是,如何根据条件控制日期格式,例如每条消息的URL(更确切地说来自外部)。我知道在webservice-method(第一个代码块)中我正在与哪个国家进行交谈但不在序列化程序中......

结果

我在下面提供的解决方案确实是一个可以解决我的问题的解决方案,但我确实相信它不可能在Mule 3.5.2 EE中运行。但是,如果使用Mule 3.6.0或3.7.0(现在似乎是最新版本),这可能是您的解决方案,也可能是其他可能使用其他框架的解决方案。

评论中没有提及,但我确实尝试评论出“String country = uriInfo.getPathParameters()。getFirst(”country“);”和硬编码的国家到“不”,我确实得到了挪威日期格式。当用“se”重新编译时,我确实得到了瑞典语格式,所以即使我无法使用它,解决方案也能正常工作。

UPDATE2

我确实与骡子支持进行了讨论。在Mule和更早版本的3.5.x中,运行了jersey-json和jackson-jaxrs,它加载时有点随机(并且取决于不同的环境)。可以从$ MULE_HOME / lib / opt中删除jersey-json。 3.6.x及更高版本只会发送杰克逊jaxrs。

当我坐在一个有许多流程的系统上时,我没有时间测试是否删除了jersey-json没有破坏任何东西(因为删除文件会影响所有流程,而不仅仅是这个流程)。基本上3.6.x及更高版本将更好地控制泽西岛(选择提供商等),并使其成为可能。

1 个答案:

答案 0 :(得分:1)

  

&#34; ...如何根据条件控制日期格式,例如每条消息的URL(更准确地说来自外部)&#34;

虽然工作稍微多一点,但一种方法是为每种类型的请求创建不同的ObjectMapper配置。要确定将使用哪一个,我们可以在ContextResolver内做出决定。我们可以在解析器中注入UriInfo,以获取@PathParam("country")的值。然后从中做出决定,将使用哪个映射器。例如

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    private final ObjectMapper sweMapper;
    private final ObjectMapper norMapper;
    private final ObjectMapper defaultMapper;

    @Context
    private UriInfo uriInfo;

    public ObjectMapperContextResolver() {
        defaultMapper = new ObjectMapper();

        sweMapper = new ObjectMapper();
        SimpleModule sweModule = new SimpleModule("SweModule", new Version(1,0,0,null));
        sweModule.addDeserializer(Date.class, new JsonDateDeserializer(sweFormat));
        sweModule.addSerializer(Date.class, new JsonDateSerializer(sweFormat));
        sweMapper.registerModule(sweModule);

        norMapper = new ObjectMapper();
        SimpleModule norModule = new SimpleModule("NorModule", new Version(1,0,0,null));
        norModule.addDeserializer(Date.class, new JsonDateDeserializer(norFormat));
        norModule.addSerializer(Date.class, new JsonDateSerializer(norFormat));
        norMapper.registerModule(norModule);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        String country = uriInfo.getPathParameters().getFirst("country");
        if (country == null) {
            return defaultMapper;
        }

        switch (country) {
            case "se": return sweMapper;
            case "no": return norMapper;
            default: return defaultMapper;
        }
    }  
}

我们使用三个映射器的原因是一个,它们的创建成本很高。其次,配置它们不是线程安全的。由于ContextResolver将是一个单例,因此只有一个映射器将用于应用程序。所以我们只为不同的案例创建三个。

如果你走这条路,你还应该记得从字段中删除序列化注释。

更新

所以对于Jersey 2.6,似乎上述解决方案存在问题。它只是在启动时失败。我能找到的解决方案是使用此依赖

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>${jersey-version}</version>
</dependency>

似乎加载此模块的某些部分会导致其失败。而只是使用Pure Jackson依赖(上面实际上是拉入并使用它自己)。

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.13</version>
</dependency>

注意: jersey-json:1.6使用上述依赖项的1.7.1。我刚切换到使用最新的1.x版本。所以你可能想也可能不想把它换回来。

摆脱旧工件的任何可能性,即

<init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
</init-param>

将Jackson软件包添加为扫描包

<init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>
        com.your.packages,
        org.codehaus.jackson.jaxrs
    </param-value>
</init-param>

或者,如果您使用的是某些特定于Mule的配置,请注册这些

  • org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
  • org.codehaus.jackson.jaxrs.JacksonMappingExceptionMapper
  • org.codehaus.jackson.jaxrs.JacksonParseExceptionMapper