解决Apache CXF 不支持传递java.sql.Timestamp和java.util.HashMap类型问题

本文介绍如何在Apache CXF中实现Timestamp和Map类型的适配,以支持WebService的发布。通过自定义适配器,实现了Timestamp与String及Map与String之间的相互转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

在项目中使用Apache开源的Services Framework CXF来发布WebService,CXF能够很简洁与Spring Framework 集成在一起,在发布WebService的过程中,发布的接口的入参有些类型支持不是很好,比如Timestamp和Map。这个时候我们就需要编写一些适配来实行类型转换。

 

TimestampAdapter.java

 
package com.loongtao.general.crawler.webservice.utils;

import java.sql.Timestamp;

import javax.xml.bind.annotation.adapters.XmlAdapter;

/**
 * <java.sql.Timestamp类型转换> <功能详细描述>
 * 在相应的字段前面  加上  @XmlJavaTypeAdapter(TimestampAdapter.class)
 * @author Lilin
 */
public class TimestampAdapter extends XmlAdapter<String, Timestamp> {

    /**
     * <一句话功能简述> <功能详细描述>
     * 
     * @param time
     * @return
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    public String marshal(Timestamp time) throws Exception {
        return DateUtil.timestamp2Str(time);
    }

    /**
     * <一句话功能简述> <功能详细描述>
     * 
     * @param v
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    public Timestamp unmarshal(String str) throws Exception {
        return DateUtil.str2Timestamp(str);
    }
}
 

DateUtil.java

 
package com.loongtao.general.crawler.webservice.utils;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;

import org.apache.log4j.Logger;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author Lilin
 * @version
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class DateUtil {
    /**
     * 注释内容
     */
    private static final Logger log = Logger.getLogger(DateUtil.class);
    /**
     * 默认日期格式
     */
    private static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * <默认构造函数>
     */
    private DateUtil() {
    }

    /**
     * <字符串转换成日期> <如果转换格式为空,则利用默认格式进行转换操作>
     * 
     * @param str
     *            字符串
     * @param format
     *            日期格式
     * @return 日期
     * @see [类、类#方法、类#成员]
     */
    public static Date str2Date(String str, String format) {
        if (null == str || "".equals(str)) {
            return null;
        }
        // 如果没有指定字符串转换的格式,则用默认格式进行转换
        if (null == format || "".equals(format)) {
            format = DEFAULT_FORMAT;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = sdf.parse(str);
            return date;
        } catch (ParseException e) {
            log.error("Parse string to date error!String : " + str);
        }

        return null;
    }

    /**
     * <一句话功能简述> <功能详细描述>
     * 
     * @param date
     *            日期
     * @param format
     *            日期格式
     * @return 字符串
     * @see [类、类#方法、类#成员]
     */
    public static String date2Str(Date date, String format) {
        if (null == date) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * <时间戳转换为字符串> <功能详细描述>
     * 
     * @param time
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static String timestamp2Str(Timestamp time) {
        Date date = new Date(time.getTime());
        return date2Str(date, DEFAULT_FORMAT);
    }

    /**
     * <一句话功能简述> <功能详细描述>
     * 
     * @param str
     * @return
     * @see [类、类#方法、类#成员]
     */
    public static Timestamp str2Timestamp(String str) {
        Date date = str2Date(str, DEFAULT_FORMAT);
        return new Timestamp(date.getTime());
    }
}
 

在具体的Java Bean 中,通过@XmlJavaTypeAdapter注解来通知CXF进行类型转换,具体请看ErrInfo中的属性timestamp的getter 和setter

 
/*   
 * Copyright (c) 2014-2024 . All Rights Reserved.   
 *   
 * This software is the confidential and proprietary information of   
 * LoongTao. You shall not disclose such Confidential Information   
 * and shall use it only in accordance with the terms of the agreements   
 * you entered into with LoongTao.   
 *   
 */
package com.loongtao.general.crawler.webservice.vo;

import java.io.Serializable;
import java.sql.Timestamp;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import com.loongtao.general.crawler.webservice.utils.TimestampAdapter;

/**
 * @declare: 下载失败信息<br>
 * @author: cphmvp
 * @version: 1.0
 * @date: 2014年9月22日下午3:47:26
 */
public class ErrInfo implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -5298849636495962631L;
    private String ip;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getArticleMediaId() {
        return articleMediaId;
    }

    public void setArticleMediaId(int articleMediaId) {
        this.articleMediaId = articleMediaId;
    }
    
    @XmlJavaTypeAdapter(TimestampAdapter.class)
    public Timestamp getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Timestamp timestamp) {
        this.timestamp = timestamp;
    }

    private String url;
    private int articleMediaId;
    private Timestamp timestamp;

}
 

这个时候CXF解析Java Bean ErrInfo的时候,解析到@XmlJavaTypeAdapter注解时候就会以TimestampAdapter这个适配器来进行Timestamp与String之间的转换。

Map:

用xstream将Map转换成String

 
package com.loongtao.general.crawler.webservice.utils;

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.apache.cxf.aegis.type.java5.XmlType;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import javax.xml.bind.annotation.XmlAccessType;  
import javax.xml.bind.annotation.XmlAccessorType;  

/**
 * <数据模型转换> <Map<String,Object> 与 String之间的转换>
 * 
 * @author Lilin
 * @version
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@XmlType(name = "MapAdapter")
@XmlAccessorType(XmlAccessType.FIELD)
public class MapAdapter extends XmlAdapter<String, Map<String, Object>> {
    /**
     * Convert a bound type to a value type. 转换JAXB不支持的对象类型为JAXB支持的对象类型
     * 
     * @param map
     *            map The value to be convereted. Can be null.
     * @return String
     * @throws Exception
     *             if there's an error during the conversion. The caller is
     *             responsible for reporting the error to the user through
     *             {@link javax.xml.bind.ValidationEventHandler}.
     */
    public String marshal(Map<String, Object> map) throws Exception {
        XStream xs = new XStream(new DomDriver());
        return xs.toXML(map);
    }

    /**
     * Convert a value type to a bound type. 转换JAXB支持的对象类型为JAXB不支持的的类型
     * 
     * @param model
     *            The value to be converted. Can be null.
     * @return Map<String,Object>
     * @throws Exception
     *             if there's an error during the conversion. The caller is
     *             responsible for reporting the error to the user through
     *             {@link javax.xml.bind.ValidationEventHandler}.
     */
    @SuppressWarnings("unchecked")
    public Map<String, Object> unmarshal(String model) throws Exception {
        XStream xs = new XStream(new DomDriver());
        return (HashMap) xs.fromXML(model);
    }
}
 
原文:http://www.cnblogs.com/gisblogs/p/3988128.html
### Java中 `org.apache.cxf.interceptor.Fault` 错误分析 当遇到 `org.apache.cxf.interceptor.Fault` 错误并伴随 `java.lang.String cannot be cast to` 的提示时,通常表明在 CXF WebService 中存在数据类型的不匹配问题。以下是可能的原因及其解决方案: #### 1. 数据类型不一致 如果客户端传递的数据类型与服务端期望的类型不符,则可能导致此类错误。例如,在引用[2]中提到的情况[^2],字符串被错误地解析为 JSON 对象。 - **原因**: 客户端发送的是原始字符串而非实际的对象实例。 - **解决方法**: - 确保客户端服务端定义的 DTO 类型完全一致。 - 如果使用了自动生成的 WSDL 文件,请重新生成客户端代码以同步最新的服务端结构。 ```java // 示例:确保对象正确序列化反序列化 JSONObject jsonObject = new JSONObject(); jsonObject.put("key", "value"); String jsonString = jsonObject.toJSONString(); // 反序列化回对象 JSONObject parsedObject = JSON.parseObject(jsonString); System.out.println(parsedObject.getString("key")); ``` --- #### 2. XML Wrapper 元素不匹配 CXF 使用 SOAP 协议传输数据时,可能会因为 XML Wrapper 元素名称不同而导致异常。例如,引用[3]中的情况[^3]描述了一个类似的场景。 - **原因**: 方法签名或参数封装方式不符合预期。 - **解决方法**: - 检查服务端接口是否正确标注了 `@WebParam` `@XmlElementWrapper` 注解。 - 验证 WSDL 文件中定义的服务契约是否与实现保持一致。 ```java @WebService(targetNamespace = "http://webservice/") public interface HelloService { @WebMethod public String sayHello(@WebParam(name = "name") String name); } ``` --- #### 3. 序列化/反序列化机制冲突 某些情况下,即使数据类型看似匹配,但由于不同的库处理逻辑差异(如 FastJSON、Jackson 或 JAXB),仍可能出现无法转换的问题。 - **原因**: 不同框架对同一数据格式的理解可能存在偏差。 - **解决方法**: - 统一项目中使用的序列化工具版本。 - 明确指定输入输出的内容类型(Content-Type)。例如,设置 HTTP 请求头为 `application/json` 或 `text/xml`。 ```xml <jaxb:globalBindings generateElementProperty="false"/> <!-- 上述配置可以避免不必要的 JAXBElement 封装 --> ``` --- #### 4. 自定义异常处理器 为了更好地捕获调试这类问题,可以在 CXF 中引入自定义拦截器来记录详细的上下文信息。 - **实现步骤**: - 创建一个继承自 `AbstractPhaseInterceptor<Message>` 的类。 - 在其中重写 `handleMessage` 方法,用于捕获潜在的类型转换错误。 ```java import org.apache.cxf.interceptor.AbstractPhaseInterceptor; import org.apache.cxf.message.Message; public class CustomFaultInterceptor extends AbstractPhaseInterceptor<Message> { public CustomFaultInterceptor() { super(Phase.RECEIVE); } @Override public void handleMessage(Message message) throws Fault { try { Object body = message.getContent(List.class).get(0); if (body instanceof String && !((String) body).startsWith("{")) { throw new RuntimeException("Invalid payload format!"); } } catch (Exception e) { throw new Fault(e); } } } ``` --- ### 总结 针对 `org.apache.cxf.interceptor.Fault` 错误以及 `java.lang.String cannot be cast to` 提示,应重点排查以下几个方面: - 数据类型一致性; - XML Wrapper 元素命名规则; - 序列化/反序列化的兼容性; - 引入定制化日志或拦截器辅助诊断。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值