CXF学习04---处理MAP等CXF无法自动转换的复合数据类型的形参和返回值

本文介绍了如何在CXF WebService接口中处理Map等复合数据类型的形参和返回值,通过@XmlJavaTypeAdapter注解配合自定义转换器,实现了CXF无法自动转换的数据类型的支持。

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

当在WebService的接口定义中使用到了Map接口,如下所示

Map<String,Cat> getAllCats();

此时运行服务器端,会报如下错误,指出CXF对Map接口不支持。

2014-5-2 17:11:38 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://impl.cxf.ws.onyas.com/}HelloWorldWs from class com.onyas.ws.cxf.HelloWorld
Exception in thread "main" javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException
	at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:371)
	at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:251)
	at org.apache.cxf.jaxws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:155)
	at javax.xml.ws.Endpoint.publish(Endpoint.java:170)
	at onyas.ServerMain.main(ServerMain.java:13)
Caused by: org.apache.cxf.service.factory.ServiceConstructionException
	at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:341)
	at org.apache.cxf.service.factory.AbstractServiceFactoryBean.initializeDataBindings(AbstractServiceFactoryBean.java:86)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.buildServiceFromClass(ReflectionServiceFactoryBean.java:490)
	at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.buildServiceFromClass(JaxWsServiceFactoryBean.java:704)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:550)
	at org.apache.cxf.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:265)
	at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:215)
	at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:102)
	at org.apache.cxf.frontend.ServerFactoryBean.create(ServerFactoryBean.java:159)
	at org.apache.cxf.jaxws.JaxWsServerFactoryBean.create(JaxWsServerFactoryBean.java:211)
	at org.apache.cxf.jaxws.EndpointImpl.getServer(EndpointImpl.java:456)
	at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:334)
	... 4 more
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
java.util.Map is an interface, and JAXB can't handle interfaces.
	this problem is related to the following location:
		at java.util.Map
		at private java.util.Map com.onyas.ws.cxf.jaxws_asm.GetAllCatsResponse._return
		at com.onyas.ws.cxf.jaxws_asm.GetAllCatsResponse
java.util.Map does not have a no-arg default constructor.
	this problem is related to the following location:
		at java.util.Map
		at private java.util.Map com.onyas.ws.cxf.jaxws_asm.GetAllCatsResponse._return
		at com.onyas.ws.cxf.jaxws_asm.GetAllCatsResponse

	at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:66)
	at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:422)
	at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:270)
	at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:103)
	at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:81)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
	at javax.xml.bind.ContextFinder.find(ContextFinder.java:376)
	at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
	at org.apache.cxf.common.jaxb.JAXBContextCache.createContext(JAXBContextCache.java:340)
	at org.apache.cxf.common.jaxb.JAXBContextCache.getCachedContextAndSchemas(JAXBContextCache.java:228)
	at org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:482)
	at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:339)
	... 15 more

如果在CXF开发中遇到不支持的类型,则需要我们自已来处理。处理思路是:提供一个转换器,这个转换器负责把CXF处理不了的类型转换成CXF处理的了的类型。

步骤:

1、使用@XmlJavaTypeAdapter来修饰CXF无法处理的类型,使用该Annotation时,通过value属性指定一个转换器

2、实现自己的转换器,需要开发一个CXF能处理的类型

代码如下所示:

1、加注释:

package com.onyas.ws.cxf;

import java.util.List;
import java.util.Map;

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

import com.onyas.ws.cxf.domain.Cat;
import com.onyas.ws.cxf.domain.User;
import com.onyas.ws.cxf.util.MapAdapter;

@WebService
public interface HelloWorld {
	
	String sayHi(String name);

	List<Cat> getCatsByUser(User user);
	
	@XmlJavaTypeAdapter(MapAdapter.class) Map<String,Cat> getAllCats();
}


实现类:

@Override
	public Map<String, Cat> getAllCats() {
		Map<String, Cat> result = new HashMap<String, Cat>();
		int i = 1;
		for (List<Cat> cats : catDb.values()) {
			for (Cat cat : cats) {
				result.put("第" + i++ + "只猫", cat);
			}
		}
		return result;
	}



2、写转换器:

package com.onyas.ws.cxf.util;

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

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

import com.onyas.ws.cxf.domain.Cat;
import com.onyas.ws.cxf.util.StringCat.Entry;
/**
 * ValueType 指的是CXF能处理的类型 
 * BoundType 指的是CXF无法处理的类型
 * StringCat 是自已定义的Bean
 * 
 * 该转换器主要完成StringCat与Map<String,Cat>类型的相互转换
 */
public class MapAdapter extends XmlAdapter<StringCat, Map<String,Cat>> {

	/**
	 * 把Map<String, Cat>转换成StringCat
	 */
	@Override
	public StringCat marshal(Map<String, Cat> v) throws Exception {
		StringCat sc = new StringCat();
		for(String s:v.keySet()){
			sc.getEntries().add(new Entry(s,v.get(s)));
		}
		return sc;
	}

	/**
	 * 把StringCat转换成Map<String, Cat>
	 */
	@Override
	public Map<String, Cat> unmarshal(StringCat v) throws Exception {
		Map<String,Cat> result = new HashMap<String,Cat>();
		for(Entry entry :v.getEntries()){
			result.put(entry.getKey(), entry.getValue());
		}
		return result;
	}


}

3、自定义的类型

package com.onyas.ws.cxf.util;

import java.util.ArrayList;
import java.util.List;

import com.onyas.ws.cxf.domain.Cat;

public class StringCat {

	private List<Entry> entries=new ArrayList<Entry>();

	public List<Entry> getEntries() {
		return entries;
	}
	public void setEntries(List<Entry> entries) {
		this.entries = entries;
	}
	
	public static class Entry{
		
		private String key;
		private Cat value;
		
		public Entry() {
		}
		
		public Entry(String key, Cat cat) {
			this.key = key;
			this.value = cat;
		}
		public String getKey() {
			return key;
		}
		public void setKey(String key) {
			this.key = key;
		}
		public Cat getValue() {
			return value;
		}
		public void setValue(Cat value) {
			this.value = value;
		}
	}
}
4、发布服务端

客户端用wsdl2java重新生成,然后如下

StringCat sc = hw.getAllCats();
		for(Entry entry:sc.getEntries()){
			System.out.println(entry.getKey()+"--"+entry.getValue().getName());
		}


代码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值