I have an entity class called Activity, the class was deserialising and working fine untill i decided to add an id field of type int to the entity. The getters and setters for this field are public and seem to be fine, however when I run my tests for creating an object from the client side I get this deserialisation error as shown below. I am following a REST tutorial using jersey.
I have checked the vissibility of the setters and getters for this field they neither are package private nor are are they private.
This is the error that I am getting:
javax.ws.rs.ProcessingException: Error deserializing object from entity stream. at org.glassfish.jersey.jsonb.internal.JsonBindingProvider.readFrom(JsonBindingProvider.java:77) at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:233) at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:212) at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:132) at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1067) at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:850) at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:784) at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:297) at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:91) at org.glassfish.jersey.internal.Errors.process(Errors.java:292) at org.glassfish.jersey.internal.Errors.process(Errors.java:274) at org.glassfish.jersey.internal.Errors.process(Errors.java:205) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:365) at org.glassfish.jersey.client.InboundJaxrsResponse.runInScopeIfPossible(InboundJaxrsResponse.java:240) at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:88) at tzpl.client.ActivityClient.create(ActivityClient.java:54) at tzpl.client.ActivityClientTest.testCreate(ActivityClientTest.java:62) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: javax.json.bind.JsonbException: Can't deserialize JSON array into: class tzpl.model.Activity at org.eclipse.yasson.internal.serializer.DeserializerBuilder.build(DeserializerBuilder.java:141) at org.eclipse.yasson.internal.Unmarshaller.deserializeItem(Unmarshaller.java:60) at org.eclipse.yasson.internal.Unmarshaller.deserialize(Unmarshaller.java:51) at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:45) at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:85) at org.glassfish.jersey.jsonb.internal.JsonBindingProvider.readFrom(JsonBindingProvider.java:75) ... 38 more Process finished with exit code 255
This is the Activity Entity:
package tzpl.model;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Activity {
private int id; private String description; private int duration; private boolean worthIt; private User user; public Activity(){ } public Activity (int id, String description, int duration, boolean worthIt){ this.description = description; this.duration = duration; this.worthIt = worthIt; this.id = id; } @XmlElement(name="id") public int getId() { return id; } public void setId(int id) { this.id = id; } @XmlElement(name="user") public User getUser() { return user; } public void setUser(User user) { this.user = user; } @XmlElement(name="verdict") public boolean isWorthIt() { return worthIt; } public void setWorthIt(boolean worthIt) { this.worthIt = worthIt; } @XmlElement(name="desc") public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @XmlElement(name="time-taken") public int getDuration() { return duration; } public void setDuration(int duration) { this.duration = duration; }
}
This is the client that I am trying to use to get my activity object;
package tzpl.client; import tzpl.model.Activity; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.List; public class ActivityClient { private Client client;
public ActivityClient() { client = ClientBuilder.newClient(); } public Activity get(String id) { WebTarget target = client.target("http://localhost:8080/myapp" + "/activities"); Response response = target.path("activity/" + id).request(MediaType.APPLICATION_JSON).get(Response.class); if (response.getStatus() != 200) { throw new RuntimeException(response.getStatus() + ": An error was" + " encountered on the server."); } return response.readEntity(Activity.class); } public List<Activity> get() { WebTarget target = client.target("http://localhost:8080/myapp"); List<Activity> response = target.path("activities/").request(MediaType.APPLICATION_JSON).get(List.class); return response; } public Activity create(Activity activity) { WebTarget target = client.target("http://localhost:8080/myapp" + "/activities/"); Response response = target.path("activity").request(MediaType.APPLICATION_JSON).post(Entity.entity(activity, MediaType.APPLICATION_JSON)); if (response.getStatus() != 200) { throw new RuntimeException(response.getStatus() + ": there was an" + " error on the server."); } return response.readEntity(Activity.class); } public Activity update(Activity activity) { WebTarget target = client.target("http://localhost:8080/myapp" + "/activities/"); Response response = target.path("activity/"+activity.getId()).request(MediaType.APPLICATION_JSON).put(Entity.entity(activity, MediaType.APPLICATION_JSON)); if (response.getStatus() != 200) { throw new RuntimeException(response.getStatus() + ": there was " + "an" + " error on the server."); } return response.readEntity(Activity.class); }
}
I am running tests for the testCreate method in my client test as shown below:
package tzpl.client; import org.junit.Test; import tzpl.model.Activity; import tzpl.repository.ActivityRepository; import tzpl.repository.ActivityResourceStub; import java.util.List; import static org.junit.Assert.assertNotNull; public class ActivityClientTest { @Test public void testPut(){ ActivityRepository activityRepository = new ActivityResourceStub(); Activity activity = new Activity(6,"Mountain climbing", 45, true); Activity activity2 = activityRepository.listAllActivities().get(2); ActivityClient client = new ActivityClient(); activity2 = client.update(activity2); assertNotNull(activity2); } @Test public void testGet(){ ActivityClient client = new ActivityClient(); Activity activity = client.get("1"); System.out.println(activity.getDescription()); assertNotNull(activity); } @Test public void testGetList(){ ActivityClient client = new ActivityClient(); List<Activity> activities = client.get(); System.out.println(activities); assertNotNull(activities); } @Test (expected=RuntimeException.class) public void testGetWithBadRequest(){ ActivityClient client = new ActivityClient(); client.get(""); } @Test(expected=RuntimeException.class) public void testGetWithNotFound(){ ActivityClient client = new ActivityClient(); client.get("777"); } @Test public void testCreate(){ ActivityClient client = new ActivityClient(); Activity activity = new Activity(7,"Skiing", 20, false); activity = client.create(activity); assertNotNull(activity); } }
Before I even assert the nullity or lack thereof of activity, I get an error from the Activity client complaining that it cannot deserialise the incoming Jason stream. I have the following dependencies in the pom.xml. I clearly have a dependency for working with jason as seen in the pom below and like I mentioned the tests only broke after the introduction of the id field.
<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>tzpl</groupId> <artifactId>com.tzpl</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>com.tzpl</name> <dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey</groupId> <artifactId>jersey-bom</artifactId> <version>${jersey.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-grizzly2-http</artifactId> </dependency> <dependency> <groupId>org.glassfish.jersey.inject</groupId> <artifactId>jersey-hk2</artifactId> </dependency> <!-- uncomment this to get JSON support:--> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-binding</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.3.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <inherited>true</inherited> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>tzpl.Main</mainClass> </configuration> </plugin> </plugins> </build> <properties> <jersey.version>2.28</jersey.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
I need help on how wto overcome this deserialisation error.
Advertisement
Answer
The root cause is quite clear:
Can’t deserialize JSON array into: class tzpl.model.Activity
Deserializer sees that next thing that comes is an array, but you say it should be an Activity object, so it cannot work.