Well, the solution is quite simpler than I expected: Just make SinglyLinkedListNode implement java.util.List or java.util.Collection , Jackson will automatically deserialize it!
This idea comes from Tatu Saloranta, the discussion post is here, special thanks to him!
Here is the complete code of SinglyLinkedListNode:
packageorg.algorithmhub.customized_collection;importjava.util.*;/** * 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 */publicclassSinglyLinkedListNode<E>extendsAbstractSequentialList<E>implementsCloneable,java.io.Serializable{publicEvalue;publicSinglyLinkedListNode<E>next;/** * Constructs an empty list. */publicSinglyLinkedListNode(){value=null;next=null;}/** * Constructs an list with one element. */publicSinglyLinkedListNode(finalEvalue,SinglyLinkedListNode<E>next){this.value=value;this.next=next;}/** * 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 */publicSinglyLinkedListNode(Collection<?extendsE>c){this();addAll(c);}/** * @inheritDoc */publicintsize(){intsize=0;if(value==null)returnsize;SinglyLinkedListNode<E>cur=this;while(cur!=null){size++;cur=cur.next;}returnsize;}/** * Tells if the argument is the index of a valid position for an * iterator or an add operation. */privatebooleanisPositionIndex(intindex){returnindex>=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. */privateStringoutOfBoundsMsg(intindex){return"Index: "+index+", Size: "+size();}privatevoidcheckPositionIndex(intindex){if(!isPositionIndex(index))thrownewIndexOutOfBoundsException(outOfBoundsMsg(index));}privateclassPositionInfo{privateSinglyLinkedListNode<E>prev;privateSinglyLinkedListNode<E>cur;privatePositionInfo(SinglyLinkedListNode<E>prev,SinglyLinkedListNode<E>cur){this.prev=prev;this.cur=cur;}}/** * Returns the (non-null) Node at the specified element index. */PositionInfonode(intindex){checkPositionIndex(index);if(this.value==null)returnnewPositionInfo(null,null);SinglyLinkedListNode<E>prev=newSinglyLinkedListNode<E>(null,this);SinglyLinkedListNode<E>cur=this;for(inti=0;i<index;i++){prev=prev.next;cur=cur.next;}returnnewPositionInfo(prev,cur);}/** * @inheritDoc */publicListIterator<E>listIterator(intindex){checkPositionIndex(index);returnnewListItr(index);}privateclassListItrimplementsListIterator<E>{privateSinglyLinkedListNode<E>prev;privateSinglyLinkedListNode<E>cur;privateintexpectedModCount=modCount;ListItr(intindex){assertisPositionIndex(index);finalPositionInfopositionInfo=node(index);prev=positionInfo.prev;cur=positionInfo.cur;}publicbooleanhasNext(){returncur!=null;}publicEnext(){checkForComodification();if(!hasNext())thrownewNoSuchElementException();finalEresult=cur.value;cur=cur.next;returnresult;}publicbooleanhasPrevious(){thrownewUnsupportedOperationException();}publicEprevious(){thrownewUnsupportedOperationException();}publicintnextIndex(){thrownewUnsupportedOperationException();}publicintpreviousIndex(){thrownewUnsupportedOperationException();}publicvoidremove(){thrownewUnsupportedOperationException();}publicvoidset(Ee){thrownewUnsupportedOperationException();}publicvoidadd(Ee){checkForComodification();if(prev==null){// empty listSinglyLinkedListNode.this.value=e;SinglyLinkedListNode.this.next=null;cur=SinglyLinkedListNode.this;}elseif(cur==null){// linkLastprev.next=newSinglyLinkedListNode<>(e,null);}else{finalSinglyLinkedListNode<E>newNode=newSinglyLinkedListNode<>(e,cur.next);cur.next=newNode;}modCount++;expectedModCount++;}finalvoidcheckForComodification(){if(modCount!=expectedModCount)thrownewConcurrentModificationException();}}}
packageorg.algorithmhub.customized_collection;importcom.fasterxml.jackson.core.type.TypeReference;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.junit.Test;importstaticorg.junit.Assert.assertEquals;importjava.io.IOException;importjava.util.ArrayList;importjava.util.Arrays;publicclassSinglyLinkedListTest{@TestpublicvoidsinglyLinkedListTest()throwsIOException{finalObjectMapperobjectMapper=newObjectMapper();finalSinglyLinkedListNode<Integer>emptyList=objectMapper.readValue("[]",newTypeReference<SinglyLinkedListNode<Integer>>(){});finalSinglyLinkedListNode<Integer>emptyListExpected=newSinglyLinkedListNode<>();assertEquals(emptyListExpected,emptyList);// the time complexity is O(n)finalSinglyLinkedListNode<Integer>intList=objectMapper.readValue("[1,2,3,4,5]",newTypeReference<SinglyLinkedListNode<Integer>>(){});finalSinglyLinkedListNode<Integer>intListExpected=newSinglyLinkedListNode<>(1,newSinglyLinkedListNode<>(2,newSinglyLinkedListNode<>(3,newSinglyLinkedListNode<>(4,newSinglyLinkedListNode<>(5,null)))));intListExpected.next=newSinglyLinkedListNode<>(2,newSinglyLinkedListNode<>(3,newSinglyLinkedListNode<>(4,newSinglyLinkedListNode<>(5,null))));assertEquals(intListExpected,intList);finalArrayList<SinglyLinkedListNode<Integer>>arrayOfList=objectMapper.readValue("[[1,2,3], [4,5,6]]",newTypeReference<ArrayList<SinglyLinkedListNode<Integer>>>(){});finalArrayList<SinglyLinkedListNode<Integer>>arrayOfListExpected=newArrayList(Arrays.asList(newSinglyLinkedListNode<>(Arrays.asList(1,2,3)),newSinglyLinkedListNode<>(Arrays.asList(4,5,6))));assertEquals(arrayOfListExpected,arrayOfList);}}