如何使用Jackson将JSON数组反序列化为单链表

时间:2015-06-17 08:41:11

标签: jackson

我想将JSON数组反序列化为Java中的单链表。

单链表的定义如下:

public class SinglyLinkedListNode<T> {
    public T value;
    public SinglyLinkedListNode next;
    public SinglyLinkedListNode(final T value) {
        this.value = value;
    }
}

如何将[1,2,3,4,5]等JSON字符串反序列化为单链表?

public void typeReferenceTest() throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();

    final ArrayList<Integer> intArray = objectMapper.readValue("[1,2,3,4,5]",
        new TypeReference<ArrayList<Integer>>() {});
    System.out.println(intArray);

    // How to achieve this?
    final ArrayList<Integer> intList = objectMapper.readValue("[1,2,3,4,5]",
        new TypeReference<SinglyLinkedListNode<Integer>>() {});
    System.out.println(intList);
}

此外,我希望SinglyLinkedListNode成为与ArrayList相同的一等公民,可以用于各种组合,例如HashSet<SinglyLinkedListNode<Integer>>,{{1 }}

例如,如果我想将SinglyLinkedListNode<HashMap<String, Integer>>反序列化为[[1,2,3], [4,5,6]]会怎样?

据我所知,扩展ArrayList<SinglyLinkedListNode<Integer>>的自定义反序列化器不足以实现此目的。

2 个答案:

答案 0 :(得分:0)

例如,当您希望将其反序列化为ArrayList<SinglyLinkedListNode<Integer>>时。您的代码指定了预期的类型。因此,如果重新注册SinglyLinkedListNode<Integer>的反序列化器,它将成功。

答案 1 :(得分:0)

jackson-user google group我得到@Tatu Saloranta的正确答案。

答案很简单:只需实现java.util.List接口,Jackson就会自动在JSON数组和SinglyLinkedListNode之间进行序列化/反序列化。

所以我为java.util.List实现了SinglyLinkedListNode接口,代码如下:

import java.util.*;
import java.util.function.Consumer;

/**
 * Singly Linked List.
 *
 * <p>As to singly linked list, a node can be viewed as a single node,
 * and it can be viewed as a list too.</p>
 *
 * @param <E> the type of elements held in this collection
 * @see java.util.LinkedList
 */
public class SinglyLinkedListNode<E>
    extends AbstractSequentialList<E>
    implements Cloneable, java.io.Serializable {
    public E value;
    public SinglyLinkedListNode<E> next;

    /**
     * Constructs an empty list.
     */
    public SinglyLinkedListNode() {
        value = null;
        next = null;
    }

    /**
     * Constructs an list with one elment.
     */
    public SinglyLinkedListNode(final E value) {
        this.value = value;
        next = null;
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param  c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public SinglyLinkedListNode(Collection<? extends E> c) {
        this();
        addAll(c);
    }

    /**
     * Links e as last element.
     */
    void linkLast(E e) {
        final SinglyLinkedListNode<E> l = last();
        final SinglyLinkedListNode<E> newNode = new SinglyLinkedListNode<>(e);
        if (l == null)
            this.value = e;
        else
            l.next = newNode;
        modCount++;
    }

    /**
     * Inserts element e before non-null Node succ.
     */
    void linkBefore(E e, SinglyLinkedListNode<E> succ) {
        assert succ != null;
        final SinglyLinkedListNode<E> prev = this.previous(succ);
        final SinglyLinkedListNode<E> newNode = new SinglyLinkedListNode<>(e);
        if (prev == null)
            this.value = e;
        else
            prev.next = newNode;
        modCount++;
    }

    /**
     * Return the node before x.
     *
     * @param x current node
     * @return the node before x
     */
    private SinglyLinkedListNode<E> previous(final SinglyLinkedListNode<E> x) {
        assert (x != null);
        if (size() < 2)  return null;
        if (this == x) return null;

        SinglyLinkedListNode<E> prev = new SinglyLinkedListNode<>();
        prev.next = this;
        SinglyLinkedListNode<E> cur = this;
        while (cur != x) {
            prev = prev.next;
            cur = cur.next;
        }
        return prev;
    }

    /**
     * Return the last node.
     * @return the last node.
     */
    private SinglyLinkedListNode<E> last() {
        if (size() == 0) return null;
        if (size() == 1) return this;

        SinglyLinkedListNode<E> prev = new SinglyLinkedListNode<>();
        prev.next = this;
        SinglyLinkedListNode<E> cur = this;
        while (cur != null) {
            prev = prev.next;
            cur = cur.next;
        }
        return prev;
    }

    /**
     * Unlinks non-null node x.
     */
    E unlink(SinglyLinkedListNode<E> x) {
        assert x != null;
        final E element = x.value;
        final SinglyLinkedListNode<E> next = x.next;
        final SinglyLinkedListNode<E> prev = previous(x);

        if (prev == null) {
            this.value = next.value;
            this.next = next.next;
        } else {
            prev.next = next;
        }

        x.next = null;

        modCount++;
        return element;
    }

    /**
     * @inheritDoc
     */
    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }


    private class ListItr implements ListIterator<E> {
        private SinglyLinkedListNode<E> lastReturned;
        private SinglyLinkedListNode<E> next;
        private int nextIndex;
        private int expectedModCount = modCount;

        ListItr(int index) {
            assert isPositionIndex(index);
            next = (index == size()) ? null : node(index);
            nextIndex = index;
        }

        public boolean hasNext() {
            return nextIndex < size();
        }

        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.value;
        }

        public boolean hasPrevious() {
            return nextIndex > 0;
        }

        public E previous() {
            throw new UnsupportedOperationException();
        }

        public int nextIndex() {
            return nextIndex;
        }

        public int previousIndex() {
            return nextIndex - 1;
        }

        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            unlink(lastReturned);

            nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }

        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.value = e;
        }

        public void add(E e) {
            checkForComodification();
            lastReturned = null;
            if (next == null)
                linkLast(e);
            else
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }

        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (modCount == expectedModCount && nextIndex < size()) {
                action.accept(next.value);
                lastReturned = next;
                next = next.next;
                nextIndex++;
            }
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

    /**
     * @inheritDoc
     */
    public int size() {
        int size = 0;
        if (value == null) return size;

        SinglyLinkedListNode<E> cur = this;
        while (cur != null) {
            size++;
            cur = cur.next;
        }
        return size;
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * Returns the (non-null) Node at the specified element index.
     */
    SinglyLinkedListNode<E> node(int index) {
        assert isElementIndex(index);

        SinglyLinkedListNode<E> x = this;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    }

    /**
     * Tells if the argument is the index of an existing element.
     */
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size();
    }

    /**
     * Tells if the argument is the index of a valid position for an
     * iterator or an add operation.
     */
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size();
    }

    /**
     * Constructs an IndexOutOfBoundsException detail message.
     * Of the many possible refactorings of the error handling code,
     * this "outlining" performs best with both server and client VMs.
     */
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: " + size();
    }
}

这是单元测试代码:

@Test public void typeReferenceTest() throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();

    final SinglyLinkedListNode<Integer> intList = objectMapper.readValue("[1,2,3,4,5]",
        new TypeReference<SinglyLinkedListNode<Integer>>() {});
    System.out.println(intList);

    final ArrayList<SinglyLinkedListNode<Integer>> arrayOfList = objectMapper.readValue("[[1,2,3], [4,5,6]]",
        new TypeReference<ArrayList<SinglyLinkedListNode<Integer>>>() {});
    System.out.println(arrayOfList);
}

@Tatu Saloranta非常感谢你!

以下是我的原创博客Deserialize a JSON Array to a Singly Linked List