2011-02-11 62 views
6

我想轉換我的payaload內的項目列表,並將它們轉換爲hashmap。基本上,我有一個Item xml表示,它有一個ItemID列表。每個ItemID都有一個idType。但是,在我的Item類中,我希望這些ItemID被表示爲一個Map。XMLAdapter for HashMap

HashMap<ItemIDType, ItemID> 

即將到來的淨荷將代表這是一個列表

<Item>... 
    <ItemIDs> 
     <ItemID type="external" id="XYZ"/> 
     <ItemID type="internal" id="20011"/> 
    </ItemIDs> 
</Item> 

,但我想一個適配器,將轉換成一個HashMap這個

"external" => "xyz" 
"internal" => "20011" 

我現在在LinkedList

public class MapHashMapListAdapter extends XmlAdapter<LinkedList<ItemID>, Map<ItemIDType, ItemID>> { 

    public LinkedList<ItemID> marshal(final Map<ItemIDType, ItemID> v) throws Exception { ... } 

    public Map<ItemIDType, ItemID> unmarshal(final LinkedList<ItemID> v) throws Exception { ... } 

} 

但由於某種原因,當我的有效負載得到轉換時,它無法將列表轉換爲散列表。傳入的方法unmarshal的LinkedList是一個空列表。你們有什麼想法我在這裏做錯了嗎?我是否需要在這裏創建自己的數據類型來處理LinkedList?

+0

什麼意思*無法轉換*?你是否收到了一些錯誤信息,或者發生了一些你不期望的事情? 而且可能錯誤出現在您未顯示的代碼中。 – 2011-02-12 01:57:00

回答

5

而不是將Map轉換爲LinkedList您需要將其轉換爲域對象。

import java.util.HashMap; 
import java.util.Map; 
import java.util.Map.Entry; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

public final class MyMapAdapter extends 

    XmlAdapter<MyMapType,Map<Integer, String>> { 

    @Override 
    public MyMapType marshal(Map<Integer, String> arg0) throws Exception { 
     MyMapType myMapType = new MyMapType(); 
     for(Entry<Integer, String> entry : arg0.entrySet()) { 
     MyMapEntryType myMapEntryType = 
      new MyMapEntryType(); 
     myMapEntryType.key = entry.getKey(); 
     myMapEntryType.value = entry.getValue(); 
     myMapType.entry.add(myMapEntryType); 
     } 
     return myMapType; 
    } 

    @Override 
    public Map<Integer, String> unmarshal(MyMapType arg0) throws Exception { 
     HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); 
     for(MyMapEntryType myEntryType : arg0.entry) { 
     hashMap.put(myEntryType.key, myEntryType.value); 
     } 
     return hashMap; 
    } 

} 

更多信息

+0

我最終創建了自己的數據類型。 – denniss 2011-02-15 17:32:58

0

你可以參考Oracle官方文檔在這裏: XmlAdapter。他們爲HashMap提供了一個類似的例子。

0

您可以使用我的舊通用解決方案,但從不在真實項目中這樣做,它不是跨語言的(它僅適用於java客戶端+ java服務器解決方案)。 SerializableAdapler.java可以編組和解組任何java對象。對於編組,它將Java對象序列化爲String,然後將其編碼爲base64。對於反編組,它解碼base64字符串並反序列化它以獲取java對象。順便說一句,在這個解決方案中,你需要服務器和客戶端的助手(SerializableAdapler.java,Base64Coder.java)。在普通的解決方案中,您只需要一個接口,如客戶端的SomeService.java(以及服務器端的SomeService.java和SomeServiceImpl.java)。我使用http://cxf.apache.org/docs/a-simple-jax-ws-service.html進行了測試,但您可以使用其他webservices框架。

SomeService.java

package some.services.interfaces; 

import some.services.interfaces.helpers.SerializableAdapler; 

import javax.jws.WebParam; 
import javax.jws.WebService; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
import java.util.List; 
import java.util.Map; 

@WebService 
public interface SomeService { 
    String sayHi(@WebParam(name = "text") String text); 

    String sayHiToUser(@WebParam(name = "user") String user); 

    /* Advanced usecase of passing an Interface in. JAX-WS/JAXB does not 
    * support interfaces directly. Special XmlAdapter classes need to 
    * be written to handle them 
    */ 
    boolean add(@XmlJavaTypeAdapter(SerializableAdapler.class) @WebParam(name = "data") Map<String, String> data); 

    boolean addAll(@XmlJavaTypeAdapter(SerializableAdapler.class) @WebParam(name = "columns") List<String> columns, @XmlJavaTypeAdapter(SerializableAdapler.class) @WebParam(name = "datas") List<List<String>> datas); 

    @XmlJavaTypeAdapter(SerializableAdapler.class) 
    List<String> showColumns(); 

    @XmlJavaTypeAdapter(SerializableAdapler.class) 
    List<List<String>> getDatas(); 
} 

SerializableAdapler.java

package some.services.interfaces.helpers; 

import javax.xml.bind.annotation.adapters.XmlAdapter; 
import java.io.*; 

public class SerializableAdapler<BoundType> extends XmlAdapter<String,BoundType> { 
    @Override 
    public BoundType unmarshal(String v) throws Exception { 
     byte [] data = Base64Coder.decode(v); 
     ObjectInputStream ois = new ObjectInputStream(
       new ByteArrayInputStream( data)); 

     BoundType o = (BoundType)ois.readObject(); 
     ois.close(); 
     return o; 
    } 

    @Override 
    public String marshal(BoundType v) throws Exception { 
     if (v instanceof Serializable) { 
      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      ObjectOutputStream oos = new ObjectOutputStream(baos); 
      oos.writeObject(v); 
      oos.close(); 
      return new String(Base64Coder.encode(baos.toByteArray())); 
     } else { 
      throw new Exception("BoundType v is not serializable: "+v.getClass()); 
     } 
    } 
} 

Base64Coder.java

package some.services.interfaces.helpers; 

// Copyright 2003-2010 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland 
// www.source-code.biz, www.inventec.ch/chdh 
// 
// This module is multi-licensed and may be used under the terms 
// of any of the following licenses: 
// 
// EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal 
// LGPL, GNU Lesser General Public License, V2.1 or later, http://www.gnu.org/licenses/lgpl.html 
// GPL, GNU General Public License, V2 or later, http://www.gnu.org/licenses/gpl.html 
// AGPL, GNU Affero General Public License V3 or later, http://www.gnu.org/licenses/agpl.html 
// AL, Apache License, V2.0 or later, http://www.apache.org/licenses 
// BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php 
// MIT, MIT License, http://www.opensource.org/licenses/MIT 
// 
// Please contact the author if you need another license. 
// This module is provided "as is", without warranties of any kind. 
// 
// Project home page: www.source-code.biz/base64coder/java 

/** 
* A Base64 encoder/decoder. 
* 
* <p> 
* This class is used to encode and decode data in Base64 format as described in RFC 1521. 
* 
* @author 
* Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland, www.source-code.biz 
*/ 
public class Base64Coder { 

    // The line separator string of the operating system. 
    private static final String systemLineSeparator = System.getProperty("line.separator"); 

    // Mapping table from 6-bit nibbles to Base64 characters. 
    private static final char[] map1 = new char[64]; 
    static { 
     int i=0; 
     for (char c='A'; c<='Z'; c++) map1[i++] = c; 
     for (char c='a'; c<='z'; c++) map1[i++] = c; 
     for (char c='0'; c<='9'; c++) map1[i++] = c; 
     map1[i++] = '+'; map1[i++] = '/'; } 

    // Mapping table from Base64 characters to 6-bit nibbles. 
    private static final byte[] map2 = new byte[128]; 
    static { 
     for (int i=0; i<map2.length; i++) map2[i] = -1; 
     for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } 

    /** 
    * Encodes a string into Base64 format. 
    * No blanks or line breaks are inserted. 
    * @param s A String to be encoded. 
    * @return A String containing the Base64 encoded data. 
    */ 
    public static String encodeString (String s) { 
     return new String(encode(s.getBytes())); } 

    /** 
    * Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters. 
    * This method is compatible with <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>. 
    * @param in An array containing the data bytes to be encoded. 
    * @return A String containing the Base64 encoded data, broken into lines. 
    */ 
    public static String encodeLines (byte[] in) { 
     return encodeLines(in, 0, in.length, 76, systemLineSeparator); } 

    /** 
    * Encodes a byte array into Base 64 format and breaks the output into lines. 
    * @param in   An array containing the data bytes to be encoded. 
    * @param iOff   Offset of the first byte in <code>in</code> to be processed. 
    * @param iLen   Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>. 
    * @param lineLen  Line length for the output data. Should be a multiple of 4. 
    * @param lineSeparator The line separator to be used to separate the output lines. 
    * @return    A String containing the Base64 encoded data, broken into lines. 
    */ 
    public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator) { 
     int blockLen = (lineLen*3)/4; 
     if (blockLen <= 0) throw new IllegalArgumentException(); 
     int lines = (iLen+blockLen-1)/blockLen; 
     int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length(); 
     StringBuilder buf = new StringBuilder(bufLen); 
     int ip = 0; 
     while (ip < iLen) { 
      int l = Math.min(iLen-ip, blockLen); 
      buf.append(encode(in, iOff+ip, l)); 
      buf.append(lineSeparator); 
      ip += l; } 
     return buf.toString(); } 

    /** 
    * Encodes a byte array into Base64 format. 
    * No blanks or line breaks are inserted in the output. 
    * @param in An array containing the data bytes to be encoded. 
    * @return A character array containing the Base64 encoded data. 
    */ 
    public static char[] encode (byte[] in) { 
     return encode(in, 0, in.length); } 

    /** 
    * Encodes a byte array into Base64 format. 
    * No blanks or line breaks are inserted in the output. 
    * @param in An array containing the data bytes to be encoded. 
    * @param iLen Number of bytes to process in <code>in</code>. 
    * @return  A character array containing the Base64 encoded data. 
    */ 
    public static char[] encode (byte[] in, int iLen) { 
     return encode(in, 0, iLen); } 

    /** 
    * Encodes a byte array into Base64 format. 
    * No blanks or line breaks are inserted in the output. 
    * @param in An array containing the data bytes to be encoded. 
    * @param iOff Offset of the first byte in <code>in</code> to be processed. 
    * @param iLen Number of bytes to process in <code>in</code>, starting at <code>iOff</code>. 
    * @return  A character array containing the Base64 encoded data. 
    */ 
    public static char[] encode (byte[] in, int iOff, int iLen) { 
     int oDataLen = (iLen*4+2)/3;  // output length without padding 
     int oLen = ((iLen+2)/3)*4;   // output length including padding 
     char[] out = new char[oLen]; 
     int ip = iOff; 
     int iEnd = iOff + iLen; 
     int op = 0; 
     while (ip < iEnd) { 
      int i0 = in[ip++] & 0xff; 
      int i1 = ip < iEnd ? in[ip++] & 0xff : 0; 
      int i2 = ip < iEnd ? in[ip++] & 0xff : 0; 
      int o0 = i0 >>> 2; 
      int o1 = ((i0 & 3) << 4) | (i1 >>> 4); 
      int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); 
      int o3 = i2 & 0x3F; 
      out[op++] = map1[o0]; 
      out[op++] = map1[o1]; 
      out[op] = op < oDataLen ? map1[o2] : '='; op++; 
      out[op] = op < oDataLen ? map1[o3] : '='; op++; } 
     return out; } 

    /** 
    * Decodes a string from Base64 format. 
    * No blanks or line breaks are allowed within the Base64 encoded input data. 
    * @param s A Base64 String to be decoded. 
    * @return A String containing the decoded data. 
    * @throws IllegalArgumentException If the input is not valid Base64 encoded data. 
    */ 
    public static String decodeString (String s) { 
     return new String(decode(s)); } 

    /** 
    * Decodes a byte array from Base64 format and ignores line separators, tabs and blanks. 
    * CR, LF, Tab and Space characters are ignored in the input data. 
    * This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>. 
    * @param s A Base64 String to be decoded. 
    * @return An array containing the decoded data bytes. 
    * @throws IllegalArgumentException If the input is not valid Base64 encoded data. 
    */ 
    public static byte[] decodeLines (String s) { 
     char[] buf = new char[s.length()]; 
     int p = 0; 
     for (int ip = 0; ip < s.length(); ip++) { 
      char c = s.charAt(ip); 
      if (c != ' ' && c != '\r' && c != '\n' && c != '\t') 
       buf[p++] = c; } 
     return decode(buf, 0, p); } 

    /** 
    * Decodes a byte array from Base64 format. 
    * No blanks or line breaks are allowed within the Base64 encoded input data. 
    * @param s A Base64 String to be decoded. 
    * @return An array containing the decoded data bytes. 
    * @throws IllegalArgumentException If the input is not valid Base64 encoded data. 
    */ 
    public static byte[] decode (String s) { 
     return decode(s.toCharArray()); } 

    /** 
    * Decodes a byte array from Base64 format. 
    * No blanks or line breaks are allowed within the Base64 encoded input data. 
    * @param in A character array containing the Base64 encoded data. 
    * @return An array containing the decoded data bytes. 
    * @throws IllegalArgumentException If the input is not valid Base64 encoded data. 
    */ 
    public static byte[] decode (char[] in) { 
     return decode(in, 0, in.length); } 

    /** 
    * Decodes a byte array from Base64 format. 
    * No blanks or line breaks are allowed within the Base64 encoded input data. 
    * @param in A character array containing the Base64 encoded data. 
    * @param iOff Offset of the first character in <code>in</code> to be processed. 
    * @param iLen Number of characters to process in <code>in</code>, starting at <code>iOff</code>. 
    * @return  An array containing the decoded data bytes. 
    * @throws  IllegalArgumentException If the input is not valid Base64 encoded data. 
    */ 
    public static byte[] decode (char[] in, int iOff, int iLen) { 
     if (iLen%4 != 0) throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); 
     while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--; 
     int oLen = (iLen*3)/4; 
     byte[] out = new byte[oLen]; 
     int ip = iOff; 
     int iEnd = iOff + iLen; 
     int op = 0; 
     while (ip < iEnd) { 
      int i0 = in[ip++]; 
      int i1 = in[ip++]; 
      int i2 = ip < iEnd ? in[ip++] : 'A'; 
      int i3 = ip < iEnd ? in[ip++] : 'A'; 
      if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) 
       throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 
      int b0 = map2[i0]; 
      int b1 = map2[i1]; 
      int b2 = map2[i2]; 
      int b3 = map2[i3]; 
      if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) 
       throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 
      int o0 = (b0  <<2) | (b1>>>4); 
      int o1 = ((b1 & 0xf)<<4) | (b2>>>2); 
      int o2 = ((b2 & 3)<<6) | b3; 
      out[op++] = (byte)o0; 
      if (op<oLen) out[op++] = (byte)o1; 
      if (op<oLen) out[op++] = (byte)o2; } 
     return out; } 

    // Dummy constructor. 
    private Base64Coder() {} 

} // end class Base64Coder 

SomeServiceImpl.java

package some.services.implement; 

import some.services.interfaces.SomeService; 

import javax.jws.WebService; 
import java.util.*; 

@WebService(endpointInterface = "some.services.interfaces.SomeService", 
     serviceName = "SomeService") 
public class SomeServiceImpl implements SomeSerive { 
    public String sayHi(String text) { 
     return "Hi, "+text; 
    } 

    public String sayHiToUser(String user) { 
     return "Hello, "+user; 
    } 

    protected List<String> columns = null; 
    protected final List<List<String>> datas = new LinkedList<List<String>>(); 

    public boolean add(Map<String, String> data) { 
     ... 
    } 

    public boolean addAll(List<String> columns, List<List<String>> datas) { 
     ... 
    } 

    public List<String> showColumns() { 
     ... 
    } 

    public List<List<String>> getDatas() { 
     ... 
    } 
} 

P.S .:此解決方案示例適用於Java 7(不支持正常的base64支持)。請不要編輯以後的Java版本。