Skip to content

Commit b87c12e

Browse files
committed
[BAEL-2547] jackson deserialization class-casting exception
1 parent 7dd7c70 commit b87c12e

6 files changed

Lines changed: 305 additions & 0 deletions

File tree

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.baeldung.jackson.tocollection;
2+
3+
4+
import java.util.Objects;
5+
6+
public class Book {
7+
private Integer bookId;
8+
private String title;
9+
private String author;
10+
11+
public Book() {}
12+
13+
public Book(Integer bookId, String title, String author) {
14+
this.bookId = bookId;
15+
this.title = title;
16+
this.author = author;
17+
}
18+
19+
@Override
20+
public boolean equals(Object o) {
21+
if (this == o) {
22+
return true;
23+
}
24+
if (!(o instanceof Book)) {
25+
return false;
26+
}
27+
28+
Book book = (Book) o;
29+
30+
if (!Objects.equals(bookId, book.bookId)) {
31+
return false;
32+
}
33+
if (!Objects.equals(title, book.title)) {
34+
return false;
35+
}
36+
return Objects.equals(author, book.author);
37+
}
38+
39+
@Override
40+
public int hashCode() {
41+
int result = bookId != null ? bookId.hashCode() : 0;
42+
result = 31 * result + (title != null ? title.hashCode() : 0);
43+
result = 31 * result + (author != null ? author.hashCode() : 0);
44+
return result;
45+
}
46+
47+
public Integer getBookId() {
48+
return bookId;
49+
}
50+
51+
public void setBookId(Integer bookId) {
52+
this.bookId = bookId;
53+
}
54+
55+
public String getTitle() {
56+
return title;
57+
}
58+
59+
public void setTitle(String title) {
60+
this.title = title;
61+
}
62+
63+
public String getAuthor() {
64+
return author;
65+
}
66+
67+
public void setAuthor(String author) {
68+
this.author = author;
69+
}
70+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.jackson.tocollection;
2+
3+
import com.fasterxml.jackson.core.type.TypeReference;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.databind.type.CollectionType;
6+
7+
import java.io.IOException;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
public class JsonToCollectionUtil {
12+
13+
private JsonToCollectionUtil(){}
14+
15+
public static <T> List<T> jsonArrayToList(String json, Class<T> elementClass) throws IOException {
16+
ObjectMapper objectMapper = new ObjectMapper();
17+
CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, elementClass);
18+
return objectMapper.readValue(json, listType);
19+
}
20+
21+
public static <T> List<T> jsonArrayToList2(String json, Class<T> elementClass) throws IOException {
22+
return new ObjectMapper().readValue(json, new TypeReference<List<T>>() {});
23+
}
24+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[ {
2+
"bookId" : 1,
3+
"title" : "A Song of Ice and Fire",
4+
"author" : "George R. R. Martin"
5+
}, {
6+
"bookId" : 2,
7+
"title" : "The Hitchhiker's Guide to the Galaxy",
8+
"author" : "Douglas Adams"
9+
}, {
10+
"bookId" : 3,
11+
"title" : "Hackers And Painters",
12+
"author" : "Paul Graham"
13+
} ]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<ArrayList>
2+
<item>
3+
<bookId>1</bookId>
4+
<title>A Song of Ice and Fire</title>
5+
<author>George R. R. Martin</author>
6+
</item>
7+
<item>
8+
<bookId>2</bookId>
9+
<title>The Hitchhiker's Guide to the Galaxy</title>
10+
<author>Douglas Adams</author>
11+
</item>
12+
<item>
13+
<bookId>3</bookId>
14+
<title>Hackers And Painters</title>
15+
<author>Paul Graham</author>
16+
</item>
17+
</ArrayList>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.baeldung.jackson.tocollection;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.core.type.TypeReference;
5+
import com.fasterxml.jackson.databind.JsonNode;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.type.CollectionType;
8+
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
9+
import org.assertj.core.util.Lists;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import java.util.Scanner;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
19+
20+
public class DeserializeToJavaCollectionUnitTest {
21+
private ObjectMapper objectMapper;
22+
private XmlMapper xmlMapper;
23+
private List<Book> expectedBookList;
24+
25+
26+
@BeforeEach
27+
void setup() {
28+
objectMapper = new ObjectMapper();
29+
xmlMapper = new XmlMapper();
30+
expectedBookList = Lists.newArrayList(
31+
new Book(1, "A Song of Ice and Fire", "George R. R. Martin"),
32+
new Book(2, "The Hitchhiker's Guide to the Galaxy", "Douglas Adams"),
33+
new Book(3, "Hackers And Painters", "Paul Graham"));
34+
}
35+
36+
private String readFile(String path) {
37+
try (Scanner scanner = new Scanner(getClass().getResourceAsStream(path), "UTF-8")) {
38+
return scanner.useDelimiter("\\A").next();
39+
}
40+
}
41+
42+
/*====================
43+
* JSON tests
44+
*====================
45+
*/
46+
@Test
47+
void givenJsonString_whenDeserializingToList_thenThrowingClassCastException() throws JsonProcessingException {
48+
String jsonString = readFile("/to-java-collection/books.json");
49+
List<Book> bookList = objectMapper.readValue(jsonString, ArrayList.class);
50+
assertThat(bookList).size().isEqualTo(3);
51+
assertThatExceptionOfType(ClassCastException.class)
52+
.isThrownBy(() -> bookList.get(0).getBookId())
53+
.withMessageMatching(".*java.util.LinkedHashMap cannot be cast to .*com.baeldung.jackson.tocollection.Book.*");
54+
}
55+
56+
@Test
57+
void givenJsonString_whenDeserializingWithTypeReference_thenGetExpectedList() throws JsonProcessingException {
58+
String jsonString = readFile("/to-java-collection/books.json");
59+
List<Book> bookList = objectMapper.readValue(jsonString, new TypeReference<List<Book>>() {});
60+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
61+
assertThat(bookList).isEqualTo(expectedBookList);
62+
}
63+
64+
@Test
65+
void givenJsonString_whenDeserializingWithJavaType_thenGetExpectedList() throws JsonProcessingException {
66+
String jsonString = readFile("/to-java-collection/books.json");
67+
CollectionType listType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Book.class);
68+
List<Book> bookList = objectMapper.readValue(jsonString, listType);
69+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
70+
assertThat(bookList).isEqualTo(expectedBookList);
71+
}
72+
73+
@Test
74+
void givenJsonString_whenDeserializingWithConvertValueAndTypeReference_thenGetExpectedList() throws JsonProcessingException {
75+
String jsonString = readFile("/to-java-collection/books.json");
76+
JsonNode jsonNode = objectMapper.readTree(jsonString);
77+
List<Book> bookList = objectMapper.convertValue(jsonNode, new TypeReference<List<Book>>() {});
78+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
79+
assertThat(bookList).isEqualTo(expectedBookList);
80+
}
81+
82+
@Test
83+
void givenJsonString_whenDeserializingWithConvertValueAndJavaType_thenGetExpectedList() throws JsonProcessingException {
84+
String jsonString = readFile("/to-java-collection/books.json");
85+
JsonNode jsonNode = objectMapper.readTree(jsonString);
86+
List<Book> bookList = objectMapper.convertValue(jsonNode, objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Book.class));
87+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
88+
assertThat(bookList).isEqualTo(expectedBookList);
89+
}
90+
91+
/*====================
92+
* XML tests
93+
*====================
94+
*/
95+
@Test
96+
void givenXml_whenDeserializingToList_thenThrowingClassCastException() throws JsonProcessingException {
97+
String xml = readFile("/to-java-collection/books.xml");
98+
List<Book> bookList = xmlMapper.readValue(xml, ArrayList.class);
99+
assertThat(bookList).size().isEqualTo(3);
100+
assertThatExceptionOfType(ClassCastException.class)
101+
.isThrownBy(() -> bookList.get(0).getBookId())
102+
.withMessageMatching(".*java.util.LinkedHashMap cannot be cast to .*com.baeldung.jackson.tocollection.Book.*");
103+
}
104+
105+
@Test
106+
void givenXml_whenDeserializingWithTypeReference_thenGetExpectedList() throws JsonProcessingException {
107+
String xml = readFile("/to-java-collection/books.xml");
108+
List<Book> bookList = xmlMapper.readValue(xml, new TypeReference<List<Book>>() {});
109+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
110+
assertThat(bookList).isEqualTo(expectedBookList);
111+
}
112+
113+
@Test
114+
void givenXml_whenDeserializingWithConvertValueAndTypeReference_thenGetExpectedList() throws JsonProcessingException {
115+
String xml = readFile("/to-java-collection/books.xml");
116+
List node = xmlMapper.readValue(xml, List.class);
117+
List<Book> bookList = xmlMapper.convertValue(node, new TypeReference<List<Book>>() {});
118+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
119+
assertThat(bookList).isEqualTo(expectedBookList);
120+
}
121+
122+
@Test
123+
void givenXml_whenDeserializingWithConvertValueAndJavaType_thenGetExpectedList() throws JsonProcessingException {
124+
String xml = readFile("/to-java-collection/books.xml");
125+
List node = xmlMapper.readValue(xml, List.class);
126+
List<Book> bookList = xmlMapper.convertValue(node, objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Book.class));
127+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
128+
assertThat(bookList).isEqualTo(expectedBookList);
129+
}
130+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.baeldung.jackson.tocollection;
2+
3+
import org.assertj.core.util.Lists;
4+
import org.junit.jupiter.api.BeforeEach;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.io.IOException;
8+
import java.util.List;
9+
import java.util.Scanner;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
13+
14+
class JsonToCollectionUtilUnitTest {
15+
16+
private List<Book> expectedBookList;
17+
18+
19+
@BeforeEach
20+
void setup() {
21+
expectedBookList = Lists.newArrayList(
22+
new Book(1, "A Song of Ice and Fire", "George R. R. Martin"),
23+
new Book(2, "The Hitchhiker's Guide to the Galaxy", "Douglas Adams"),
24+
new Book(3, "Hackers And Painters", "Paul Graham"));
25+
}
26+
27+
private String readFile(String path) {
28+
try (Scanner scanner = new Scanner(getClass().getResourceAsStream(path), "UTF-8")) {
29+
return scanner.useDelimiter("\\A").next();
30+
}
31+
}
32+
33+
@Test
34+
void givenJsonString_whenCalljsonArrayToList_thenGetExpectedList() throws IOException {
35+
String jsonString = readFile("/to-java-collection/books.json");
36+
List<Book> bookList = JsonToCollectionUtil.jsonArrayToList(jsonString, Book.class);
37+
assertThat(bookList.get(0)).isInstanceOf(Book.class);
38+
assertThat(bookList).isEqualTo(expectedBookList);
39+
}
40+
41+
@Test
42+
void givenJsonString_whenCalljsonArrayToList2_thenGetException() throws IOException {
43+
String jsonString = readFile("/to-java-collection/books.json");
44+
List<Book> bookList = JsonToCollectionUtil.jsonArrayToList2(jsonString, Book.class);
45+
assertThat(bookList).size().isEqualTo(3);
46+
assertThatExceptionOfType(ClassCastException.class)
47+
.isThrownBy(() -> bookList.get(0).getBookId())
48+
.withMessageMatching(".*java.util.LinkedHashMap cannot be cast to .*com.baeldung.jackson.tocollection.Book.*");
49+
}
50+
51+
}

0 commit comments

Comments
 (0)