XMLAdapter для HashMap - PullRequest
       15

XMLAdapter для HashMap

6 голосов
/ 12 февраля 2011

Я хочу преобразовать список элементов внутри моей payaload и преобразовать их в хэш-карту. По сути, у меня есть представление Item xml, у которого есть список ItemID. У каждого ItemID есть idType. Однако внутри моего класса Item я хочу, чтобы эти ItemID были представлены в виде карты.

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 { ... }

}

но по какой-то причине, когда моя полезная нагрузка преобразуется, она не может преобразовать список в хэш-карту. Входящий LinkedList метода unmarshal является пустым списком. Ребята, вы понимаете, что я здесь делаю не так? Нужно ли мне создавать свой собственный тип данных для обработки LinkedList?

Ответы [ 3 ]

5 голосов
/ 12 февраля 2011

Вместо преобразования 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 голосов
/ 08 апреля 2016

Вы можете использовать мое старое универсальное решение, , но никогда не делайте этого в реальном проекте , это не кросс-язык (это только для решения java client + java server).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, но вы можете использовать другие фреймворки веб-сервисов.

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() {
        ...
    }
}

PS: этот пример решения для Java 7 (без нормальной поддержки base64).Пожалуйста, не редактируйте для более поздних версий Java.

0 голосов
/ 06 июня 2012

Вы можете обратиться к официальной документации оракула здесь: XMLAdapter . Они привели похожий пример для HashMap.

...