JsonbException: Can’t deserialize JSON array into: class

The javax.json.bind.JsonbException: Can’t deserialize JSON array into: class exception occurs when you try to convert json string data to a java object. If the json string contains an array of objects and attempts to deserialize the json string to a json object, the array of objects could not be assigned to a single java object. The deserialization  exception javax.json.bind.JsonbException: Can’t deserialize JSON array into: class is therefore thrown while binding the json data.

The program attempts to deserialize the json string into a java object. The data binding api can not deserialize the string due to the json string and the java class not matching. The spring boot application will read and interpret the json file, the error is when the parsed input is translated to the java object

We’ll see in this post about this exception javax.json.bind.JsonbException: Can’t deserialize JSON array into: class and how this exception can be resolved.



Exception

Exception in thread "main" javax.json.bind.JsonbException: Can't deserialize JSON array into: class com.yawintutor.Student
	at org.eclipse.yasson.internal.serializer.DeserializerBuilder.build(DeserializerBuilder.java:151)
	at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:66)
	at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:52)
	at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:59)
	at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:66)
	at com.yawintutor.SpringBootJsonbSimpleApplication.JSONToJavaObjectArray(SpringBootJsonbSimpleApplication.java:49)
	at com.yawintutor.SpringBootJsonbSimpleApplication.main(SpringBootJsonbSimpleApplication.java:19)


Root Cause

The exception “javax.json.bind.JsonbException: Can’t deserialize JSON array into: class com.yawintutor.Student” clearly states that during deserialization of the json string, it has some issue. The json string contains root as array of objects. In the spring boot application, it attempts to convert to a java object. Java can not allocate an array to an object.

Convert the json string into object array in the “fromJson” api. This addresses the exception.



How to reproduce this issue

In the spring boot application, add all dependency for json binding. create a json string containing objects in an array. Using “from Json” api in the program to convert json string to an object in java. The input json string includes an object list, and the program attempts to allocate to an object in java. This is going to throw out the exception.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.5.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.yawintutor</groupId>
	<artifactId>Spring-Application</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SpringBootJsonbSimple</name>
	<description>Spring Boot Project</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>javax.json.bind</groupId>
			<artifactId>javax.json.bind-api</artifactId>
		</dependency>

		<dependency>
			<groupId>org.eclipse</groupId>
			<artifactId>yasson</artifactId>
			<version>1.0.6</version>
		</dependency>

		<dependency>
			<groupId>org.glassfish</groupId>
			<artifactId>javax.json</artifactId>
			<version>1.1.4</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Student.java

package com.yawintutor;

public class Student {

	private int id;

	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

SpringBootJsonbSimpleApplication.java

package com.yawintutor;

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootJsonbSimpleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootJsonbSimpleApplication.class, args);

		JavaObjectArraytoJSON();
		JSONToJavaObjectArray();
	}

	public static void JavaObjectArraytoJSON() {
		Student student1 = new Student();
		student1.setId(100);
		student1.setName("Yawin");
		
		Student student2 = new Student();
		student2.setId(101);
		student2.setName("Spring Boot");

		Student[] studentArray = new Student[2];
		studentArray[0] = student1;
		studentArray[1] = student2;
		
		Jsonb jsonb = JsonbBuilder.create();
		String jsonString = jsonb.toJson(studentArray);
		System.out.println("Json format String : " + jsonString);
	}

	public static void JSONToJavaObjectArray() {
		String jsonString = "[{\"id\":100,\"name\":\"Yawin\"},{\"id\":101,\"name\":\"Spring Boot\"}]";

		Jsonb jsonb = JsonbBuilder.create();
		Student st = jsonb.fromJson(jsonString, Student.class);
		System.out.println(st.getId() + " " + st.getName());
	}	

Output

Exception in thread "main" javax.json.bind.JsonbException: Can't deserialize JSON array into: class com.yawintutor.Student
	at org.eclipse.yasson.internal.serializer.DeserializerBuilder.build(DeserializerBuilder.java:151)
	at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:66)
	at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:52)
	at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:59)
	at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:66)
	at com.yawintutor.SpringBootJsonbSimpleApplication.JSONToJavaObjectArray(SpringBootJsonbSimpleApplication.java:49)
	at com.yawintutor.SpringBootJsonbSimpleApplication.main(SpringBootJsonbSimpleApplication.java:19)


Solution 1

The json string includes objects in an array. Hence, type cast the json string to an array of java objects. This will resolve this exception. The code below illustrates how to transform a json string to an array of objects in java.

Student[] studentArray = jsonb.fromJson(jsonString, new Student[] {}.getClass() );

The complete java code to convert from a json string to a Java object array is shown as

SpringBootJsonbSimpleApplication.java

package com.yawintutor;

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootJsonbSimpleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootJsonbSimpleApplication.class, args);

		JavaObjectArraytoJSON();
		JSONToJavaObjectArray();
	}

	public static void JavaObjectArraytoJSON() {
		Student student1 = new Student();
		student1.setId(100);
		student1.setName("Yawin");
		
		Student student2 = new Student();
		student2.setId(101);
		student2.setName("Spring Boot");

		Student[] studentArray = new Student[2];
		studentArray[0] = student1;
		studentArray[1] = student2;
		
		Jsonb jsonb = JsonbBuilder.create();
		String jsonString = jsonb.toJson(studentArray);
		System.out.println("Json format String : " + jsonString);
	}

	public static void JSONToJavaObjectArray() {
		String jsonString = "[{\"id\":100,\"name\":\"Yawin\"},{\"id\":101,\"name\":\"Spring Boot\"}]";

		Jsonb jsonb = JsonbBuilder.create();
		Student[] studentArray = jsonb.fromJson(jsonString, new Student[] {}.getClass() );
		for(Student st : studentArray) {
			System.out.println(st.getId() + " " + st.getName());
		}
		
	}	
}

Output


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)

2020-03-16 07:51:20.073  INFO 52723 --- [           main] c.y.SpringBootJsonbSimpleApplication     : Starting SpringBootJsonbSimpleApplication on banl1691b9157 with PID 52723 (/Users/knatarajan2/STS/workspace/SpringBootJsonbSimple/target/classes started by knatarajan2 in /Users/knatarajan2/STS/workspace/SpringBootJsonbSimple)
2020-03-16 07:51:20.075  INFO 52723 --- [           main] c.y.SpringBootJsonbSimpleApplication     : No active profile set, falling back to default profiles: default
2020-03-16 07:51:20.489  INFO 52723 --- [           main] c.y.SpringBootJsonbSimpleApplication     : Started SpringBootJsonbSimpleApplication in 0.649 seconds (JVM running for 3.209)
Json format String : [{"id":100,"name":"Yawin"},{"id":101,"name":"Spring Boot"}]
100 Yawin
101 Spring Boot


Solution 2

If the json string is expected to de-serialize the java object, make sure that the json string data contains the object data. The json string should not have an object data array. The json string should be the following example.

SpringBootJsonbSimpleApplication.java

package com.yawintutor;

import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootJsonbSimpleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootJsonbSimpleApplication.class, args);

		JavaObjectArraytoJSON();
		JSONToJavaObject();
	}

	public static void JavaObjectArraytoJSON() {
		Student student1 = new Student();
		student1.setId(100);
		student1.setName("Yawin");
		
		Student student2 = new Student();
		student2.setId(101);
		student2.setName("Spring Boot");

		Student[] studentArray = new Student[2];
		studentArray[0] = student1;
		studentArray[1] = student2;
		
		Jsonb jsonb = JsonbBuilder.create();
		String jsonString = jsonb.toJson(studentArray);
		System.out.println("Json format String : " + jsonString);
	}

	public static void JSONToJavaObject() {
		String jsonString = "{\"course\":\"BCOM\",\"id\":100,\"name\":\"Yawin\"}";

		Jsonb jsonb = JsonbBuilder.create();
		Student st = jsonb.fromJson(jsonString, Student.class);
		System.out.println(st.getId() + " " + st.getName()+" "+st.getCourse().name());
	}
}

Output


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)

2021-02-24 19:44:21.170  INFO 6745 --- [           main] c.y.SpringBootJsonbSimpleApplication     : Starting SpringBootJsonbSimpleApplication on intul1807201e8 with PID 6745 (/Users/knatarajan2/STS/workspace/SpringBootJsonbSimple/target/classes started by knatarajan2 in /Users/knatarajan2/STS/workspace/SpringBootJsonbSimple)
2021-02-24 19:44:21.173  INFO 6745 --- [           main] c.y.SpringBootJsonbSimpleApplication     : No active profile set, falling back to default profiles: default
2021-02-24 19:44:21.624  INFO 6745 --- [           main] c.y.SpringBootJsonbSimpleApplication     : Started SpringBootJsonbSimpleApplication in 2.925 seconds (JVM running for 3.257)
Json format String : {"course":"BCOM","id":100,"name":"Yawin"}
100 Yawin BCOM


Solution 3

More details on how to use json binding api are explained in the links below.




Leave a Reply