我正在使用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”重新编译时,我确实得到了瑞典语格式,所以即使我无法使用它,解决方案也能正常工作。
我确实与骡子支持进行了讨论。在Mule和更早版本的3.5.x中,运行了jersey-json和jackson-jaxrs,它加载时有点随机(并且取决于不同的环境)。可以从$ MULE_HOME / lib / opt中删除jersey-json。 3.6.x及更高版本只会发送杰克逊jaxrs。
当我坐在一个有许多流程的系统上时,我没有时间测试是否删除了jersey-json没有破坏任何东西(因为删除文件会影响所有流程,而不仅仅是这个流程)。基本上3.6.x及更高版本将更好地控制泽西岛(选择提供商等),并使其成为可能。
答案 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