bhc*_*ney 5 java schema soap wsdl2java jaxb
我试图通过SOAP传递Hashmap.我正在使用CXF wsdl2java来创建我的架构.我已经为我的HashMap创建了一个包装类,因为Hashmap本身不能通过该行传递.
然后我创建了适配器来将Hashmap变形为我的wsdl的已知类型,但是当我的wsdl被创建时,它会添加一些不需要的抽象地图.以下是代码:
这是我的HashMap包装类
@XmlRootElement(name = "testTO")
public class TestTO {
private HashMap<String, Object> mapTest;
public TestTO(){
this.mapTest = new HashMap<String, Object>();
}
@XmlJavaTypeAdapter(MapAdapter.class)
public HashMap<String, Object> getMapTest() {
return mapTest;
}
public void setMapTest(HashMap<String, Object> mapTest) {
this.mapTest = mapTest;
}
}
Run Code Online (Sandbox Code Playgroud)
这是MyMap类,其中是已知的模式类型
@XmlJavaTypeAdapter(MapAdapter.class)
public class MyMap extends HashMap<String, Object>{
public final List<Entry> entryList = new ArrayList<Entry>();
}
Run Code Online (Sandbox Code Playgroud)
这是Entry List,其中包含上面的列表:
public class Entry {
@XmlAttribute
public String key;
@XmlElements({
@XmlElement(name = "byte", type = byte.class),
@XmlElement(name = "short", type = short.class),
@XmlElement(name = "int", type = int.class),
@XmlElement(name = "long", type = long.class),
@XmlElement(name = "float", type = float.class),
@XmlElement(name = "double", type = double.class),
@XmlElement(name = "char", type = char.class),
@XmlElement(name = "boolean", type = boolean.class),
@XmlElement(name = "ByteWrapper", type = Byte.class),
@XmlElement(name = "ShortWrapper", type = Short.class),
@XmlElement(name = "IntegerWrapper", type = Integer.class),
@XmlElement(name = "LongWrapper", type = Long.class),
@XmlElement(name = "FloatWrapper", type = Float.class),
@XmlElement(name = "DoubleWrapper", type = Double.class),
@XmlElement(name = "Character", type = Character.class),
@XmlElement(name = "BooleanWrapper", type = Boolean.class),
@XmlElement(name = "BigDecimal", type = BigDecimal.class),
@XmlElement(name = "String", type = String.class),
@XmlElement(name = "Date", type = Date.class)
})
public Object value;
public Entry() {
this.key = null;
this.value = null;
}
public Entry(String key, Object value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public Object getValue() {
return value;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的适配器:
public class MapAdapter extends XmlAdapter<MyMap, Map<String, Object>> {
@Override
public MyMap marshal(Map<String, Object> v) throws Exception {
MyMap myMap = new MyMap();
for ( Map.Entry<String, Object> e : v.entrySet() ) {
Entry entry = new Entry();
entry.key = e.getKey();
entry.value = e.getValue();
myMap.entryList.add(entry);
}
return myMap;
}
@Override
public Map<String, Object> unmarshal(MyMap v) throws Exception {
Map<String, Object> map = new HashMap<String,Object>();
for ( Entry e : v.entryList ) {
map.put(e.key, e.value);
}
return map;
}
}
Run Code Online (Sandbox Code Playgroud)
但是我的wsdl产生了以下内容:
<xs:element minOccurs="0" name="foo" type="tns:testTO"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="testTO">
<xs:sequence>
<xs:element minOccurs="0" name="mapTest" type="tns:myMap"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="myMap">
<xs:complexContent>
<xs:extension base="tns:hashMap">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="entryList" nillable="true" type="tns:entry"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="hashMap">
<xs:complexContent>
<xs:extension base="tns:abstractMap">
<xs:sequence/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType abstract="true" name="abstractMap">
<xs:sequence/>
</xs:complexType>
<xs:complexType name="entry">
<xs:sequence>
<xs:choice minOccurs="0">
<xs:element name="byte" type="xs:byte"/>
<xs:element name="short" type="xs:short"/>
<xs:element name="int" type="xs:int"/>
<xs:element name="long" type="xs:long"/>
<xs:element name="float" type="xs:float"/>
<xs:element name="double" type="xs:double"/>
<xs:element name="char" type="xs:unsignedShort"/>
<xs:element name="boolean" type="xs:boolean"/>
<xs:element name="ByteWrapper" type="xs:byte"/>
<xs:element name="ShortWrapper" type="xs:short"/>
<xs:element name="IntegerWrapper" type="xs:int"/>
<xs:element name="LongWrapper" type="xs:long"/>
<xs:element name="FloatWrapper" type="xs:float"/>
<xs:element name="DoubleWrapper" type="xs:double"/>
<xs:element name="Character" type="xs:unsignedShort"/>
<xs:element name="BooleanWrapper" type="xs:boolean"/>
<xs:element name="BigDecimal" type="xs:decimal"/>
<xs:element name="String" type="xs:string"/>
<xs:element name="Date" type="xs:dateTime"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="key" type="xs:string"/>
</xs:complexType>
Run Code Online (Sandbox Code Playgroud)
我已经看过我在这里找到的其他多个案例,但没有一个能够解决我的问题我甚至引用了http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/注释/适配器/ XmlAdapter.html 但是wsdl到java似乎搞乱了架构.
谢谢.
小智 5
我相信您不必使用最新的 JAXB 版本编写XmlAdapter编组/取消编组的自定义操作。Map<String, Object下面的示例对我来说效果很好。
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "foo")
public class Foo {
private Map<String, Object> map = new HashMap<String, Object>();
public Map<String, Object> getMap() {
return params;
}
}
Run Code Online (Sandbox Code Playgroud)
这产生了一个模式:
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="map">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="entry">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="key" type="xs:string"/>
<xs:element minOccurs="0" name="value" type="xs:anyType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
Run Code Online (Sandbox Code Playgroud)
然后您应该能够解组以下 xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://your.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<soapenv:Header/>
<soapenv:Body>
<foo>
<params>
<entry>
<key>string</key>
<value xsi:type="xs:string">5</value>
</entry>
<entry>
<key>integer</key>
<value xsi:type="xs:int">54</value>
</entry>
</params>
</foo>
</soapenv:Body>
</soapenv:Envelope>
Run Code Online (Sandbox Code Playgroud)
只是不要忘记 xs 和 xsi 命名空间。您甚至可以将自定义类型作为值传递,而不仅仅是简单的 xsi 类型。然后你必须确保你已经指定了正确的xsi:type.
我想出的适合我正在寻找的解决方案与 polbotinka 提到的类似,但我添加了额外的日期绑定和适配器。TestTO 类由我界面上的所有对象扩展,作为一种为每个对象以映射格式传递灵活属性的方法。这是我所做的:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="TestTO", namespace="test/common")
public abstract class TestTO {
@XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, Object> elements;
}
Run Code Online (Sandbox Code Playgroud)
然后,该类将生成如下所示的模式(这是由 CXF-Java2Wsdl 插件生成的整体 WSDL 的一部分):
<xs:complexType abstract="true" name="testTO">
<xs:sequence>
<xs:element name="elements">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="entry">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="key" type="xs:string"/>
<xs:element minOccurs="0" name="value" type="xs:anyType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
Run Code Online (Sandbox Code Playgroud)
然后我在生成过程中使用了以下绑定文件:
<jaxws:bindings wsdlLocation="wsdl/TestImpl.wsdl"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
jaxb:version="2.1">
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='http://namespace.goes.here']">
<jaxb:bindings node="//xs:complexType[@name='testTO']//xs:element[@name='elements']">
<jaxb:property>
<jaxb:baseType name="java.util.Map<String,Object>" />
</jaxb:property>
</jaxb:bindings>
<jaxb:serializable/>
</jaxws:bindings>
</jaxws:bindings>
Run Code Online (Sandbox Code Playgroud)
从 CXF-Wsdl2Java 生成的 TestTO 版本如下所示:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "testTO", propOrder = {
"elements"
})
public abstract class TestTO {
@XmlElement(required = true, type = TestTO.Elements.class)
protected Map<String, Object> elements;
public Map<String, Object> getElements() {
return elements;
}
public void setElements(Map<String, Object> value) {
this.elements = value;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"entry"
})
public static class Elements {
protected List<TestTO.Elements.Entry> entry;
public List<TestTO.Elements.Entry> getEntry() {
if (entry == null) {
entry = new ArrayList<TestTO.Elements.Entry>();
}
return this.entry;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"key",
"value"
})
public static class Entry {
protected java.lang.String key;
protected java.lang.Object value;
public java.lang.String getKey() {
return key;
}
public void setKey(java.lang.String value) {
this.key = value;
}
public java.lang.Object getValue() {
return value;
}
public void setValue(java.lang.Object value) {
this.value = value;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以现在生成的类有一个 Map 接口,它会自动转换为内部列表类。所以我想创建一个适配器来将一些数据类型转换为我想要使用的类型。在本例中,日期是特定的,因为我通常使用 JAXB 绑定文件从架构进行日期转换,但由于架构是“anyType”,因此绑定文件将不起作用。因此,上面的 MapAdapter.class 用于将地图内输入对象上的 XmlGregorianCalendars 转换为日期。
public class MapAdapter extends XmlAdapter<TestTO.Elements, Map<String, Object>>{
@Override
public Map<String, Object> unmarshal(TestTO.Elements v) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
if(v != null && v.entry != null){
for(Entry e : v.entry){
if(e.getValue() instanceof XMLGregorianCalendar)
map.put(e.getKey(), ((XMLGregorianCalendar)e.getValue()).toGregorianCalendar().getTime());
else
map.put(e.getKey(), e.getValue());
}
}
return map;
}
@Override
public TestTO.Elements marshal(Map<String, Object> v) throws Exception {
TestTO.Elements b = new TestTO.Elements();
if(v == null)
return null;
for(java.util.Map.Entry<String, Object> e : v.entrySet()){
Entry newEntry = new Entry();
newEntry.setKey(e.getKey());
newEntry.setValue(e.getValue());
b.getEntry().add(newEntry);
}
return b;
}
}
Run Code Online (Sandbox Code Playgroud)
为了让这个适配器工作,我必须有一个“生成类”的版本来模仿内部 Elements 类。所以我有一个 common.adapter.TestTO.class ,它是生成的,还有一个 common.normal.TestTO.class ,它是我的所有其他类在我的接口上扩展的类。
这是我在客户端生成中使用的插件配置:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/META-INF/wsdl/TestImpl.wsdl</wsdl>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/META-INF/binding.xml</bindingFile>
</bindingFiles>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9558 次 |
| 最近记录: |