Java 6中JAXB泛型响应类处理多类型返回的类型转换问题
解决Jersey泛型响应中动态类型Data字段的转换问题
问题根源
- 重复属性错误:JAXB默认同时绑定字段和getter/setter方法,导致
data字段被识别为两个重复属性。 - 类型转换异常:外部服务返回的XML中
data字段的文本内容被JAXB默认解析为ElementNSImpl对象,无法直接转换为String或Boolean;泛型类型擦除导致JAXB无法自动识别目标类型。
解决方案步骤
- 用
@XmlAccessorType指定JAXB仅绑定类字段,解决重复属性问题。 - 自定义
XmlAdapter实现ElementNSImpl到目标泛型类型的转换,适配动态返回的字段类型。 - 调用服务时使用
GenericType传递泛型类型信息,避免类型擦除导致的解析错误。
具体代码实现
1. 动态类型转换适配器
import javax.xml.bind.annotation.adapters.XmlAdapter; import org.w3c.dom.Element; import java.lang.reflect.ParameterizedType; public class DynamicDataAdapter<T> extends XmlAdapter<Element, T> { @Override @SuppressWarnings("unchecked") public T unmarshal(Element element) throws Exception { if (element == null) { return null; } String content = element.getTextContent().trim(); // 获取泛型实际类型 Class<T> targetType = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; // 根据目标类型转换内容 if (Boolean.class.equals(targetType) || boolean.class.equals(targetType)) { return targetType.cast(Boolean.parseBoolean(content)); } else if (String.class.equals(targetType)) { return targetType.cast(content); } // 可扩展支持其他类型(如Integer等) return null; } @Override public Element marshal(T v) throws Exception { // 若无需序列化响应,返回null即可 return null; } }
2. 泛型BaseResponse类
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlRootElement(name = "response") @XmlAccessorType(XmlAccessType.FIELD) // 指定按字段绑定,解决重复属性问题 public class BaseResponse<T> { @XmlElement(name = "code") private Integer code; @XmlElement(name = "message") private String message; @XmlElement(name = "data") @XmlJavaTypeAdapter(DynamicDataAdapter.class) // 应用自定义适配器 private T data; // JAXB必须有无参构造函数 public BaseResponse() {} // Getter & Setter public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
3. Jersey服务调用示例
import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.GenericType; import com.sun.jersey.api.client.WebResource; public class ExternalServiceClient { public static void main(String[] args) { Client client = Client.create(); WebResource resource = client.resource("http://your-external-service-url"); // 获取String类型的data响应 BaseResponse<String> stringResp = resource.get(new GenericType<BaseResponse<String>>() {}); String stringData = stringResp.getData(); // 获取Boolean类型的data响应 BaseResponse<Boolean> booleanResp = resource.get(new GenericType<BaseResponse<Boolean>>() {}); Boolean booleanData = booleanResp.getData(); } }
关键说明
@XmlAccessorType(XmlAccessType.FIELD):彻底解决"Class has two properties of the same name 'data'"错误,让JAXB仅处理类字段,忽略getter/setter的属性映射。DynamicDataAdapter:将JAXB解析出的ElementNSImpl对象转换为目标泛型类型,通过反射获取泛型实际类型,实现动态适配。GenericType:传递泛型类型信息,避免Jersey在解析响应时因类型擦除无法识别T的实际类型,确保正确绑定数据。
内容的提问来源于stack exchange,提问作者msadasjwd
相关产品推荐
相关产品推荐

