JDK8+WebLogic14c迁移后自定义JacksonContextResolver失效求助
解决WebLogic14c中自定义JacksonContextResolver失效问题
问题背景
将Web应用从JDK1.7+WebLogic12c迁移至JDK1.8+WebLogic14c后,原自定义的JacksonContextResolver(用于配置JSON映射)完全失效,JSON返回的日期格式变为yyyy-MM-ddTHH:mm:ss.SSSZ [UTC],导致REST服务调用出现类型不匹配错误。此前在WebLogic12c环境中,依赖包打包在应用内,Resolver可正常工作;现在将JAX-RS/Jersey依赖设为provided后,推测应用使用了服务器默认的ObjectMapper。
解决方案
1. 修复自定义JacksonContextResolver代码缺陷
原代码中getContext方法直接返回null,这是导致Resolver失效的核心问题——JAX-RS要求ContextResolver必须返回配置好的ObjectMapper实例。同时优化日期时区配置逻辑:
package eu.sia.mdp.backoffice.common; import java.text.SimpleDateFormat; import java.util.TimeZone; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @Provider @Produces(MediaType.APPLICATION_JSON) public class JacksonContextResolver implements ContextResolver<ObjectMapper> { private final ObjectMapper objectMapper; private static final Logger log = LoggerFactory.getLogger(JacksonContextResolver.class); public JacksonContextResolver() { this.objectMapper = new ObjectMapper() .setSerializationInclusion(Include.NON_NULL) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true) // 直接设置时区,替代原间接获取配置的方式 .setTimeZone(TimeZone.getTimeZone("CET")); // 如需指定固定日期格式,取消注释并使用正确的格式字符串(注意yyyy/dd的大小写) // SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ"); // df.setTimeZone(TimeZone.getTimeZone("CET")); // this.objectMapper.setDateFormat(df); } @Override public ObjectMapper getContext(Class<?> objectType) { // 返回配置好的ObjectMapper实例,而非null return this.objectMapper; } }
2. 调整weblogic.xml配置,优先加载应用自带依赖
修改weblogic.xml的prefer-application-packages和prefer-application-resources配置,确保应用的Jersey、Jackson类优先于服务器自带类加载,同时移除服务器JAX-RS库的强制引用:
<?xml version="1.0" encoding="UTF-8"?> <weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"> <container-descriptor> <prefer-application-packages> <package-name>org.slf4j.*</package-name> <package-name>org.apache.commons.logging.*</package-name> <!-- 取消注释,让应用优先加载Jersey相关类 --> <package-name>org.glassfish.jersey.*</package-name> <package-name>org.glassfish.hk2.*</package-name> <package-name>org.jvnet.hk2.*</package-name> <package-name>org.objectweb.asm.*</package-name> <package-name>com.sun.ws.rs.ext.*</package-name> <!-- 添加Jackson包,确保自定义配置优先 --> <package-name>com.fasterxml.jackson.*</package-name> <package-name>javax.ws.rs.*</package-name> <package-name>javax.validation.*</package-name> <package-name>org.hibernate.validator.*</package-name> </prefer-application-packages> <prefer-application-resources> <resource-name>org/slf4j/impl/StaticLoggerBinder.class</resource-name> <resource-name>org.hibernate.validator.*</resource-name> <resource-name>javax.validation.*</resource-name> <!-- 添加Jackson资源文件 --> <resource-name>com/fasterxml/jackson/**</resource-name> </prefer-application-resources> </container-descriptor> <context-root>mdp-portale-bo</context-root> <!-- 移除服务器JAX-RS库引用,避免强制使用服务器默认实现 --> <!-- <library-ref> <library-name>jax-rs</library-name> <specification-version>2.0</specification-version> <exact-match>false</exact-match> </library-ref> --> <resource-description> <res-ref-name>jdbc/MDPDB</res-ref-name> <jndi-name>jdbc/MDPDB</jndi-name> </resource-description> </weblogic-web-app>
3. 调整web.xml配置,确保Resolver被扫描加载
如果包扫描未自动识别自定义Resolver,可直接在provider.classnames中添加其全类名,确保Jersey能加载到:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" metadata-complete="false"> <servlet> <servlet-name>jersey-serlvet</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>eu.sia.mdp.backoffice</param-value> </init-param> <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value> com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider, eu.sia.mdp.backoffice.common.JacksonContextResolver </param-value> </init-param> <init-param> <param-name>jersey.config.server.tracing</param-name> <param-value>ALL</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey-serlvet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <mime-mapping> <extension>json</extension> <mime-type>application/json</mime-type> </mime-mapping> <resource-ref> <description>Database MP</description> <res-ref-name>jdbc/MPDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
4. 可选:将JAX-RS/Jersey依赖打包到应用中
若希望完全脱离WebLogic自带的JAX-RS库,可将pom.xml中相关依赖的scope从provided改为compile,让依赖打包到应用WAR包中:
<!-- JAX-RS --> <dependency> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> <version>2.0.1</version> <scope>compile</scope> </dependency> <!-- Jersey相关依赖同理修改scope --> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>${jersey.version}</version> <scope>compile</scope> </dependency>
内容的提问来源于stack exchange,提问作者pietro laforgia
相关产品推荐
相关产品推荐

