Flex Java BlazeDS date difference - java

I am trying to send a date from flex side to java using BlazeDS
field type in flex
private var _scheduleDate:Date;
I have initialized it with new Date() , and if alert it, correct date and time is displayed as on my system. now when the object is sent to java. the date get changed.
Please note that my flex application and java (JBoss server is running on same machine). If i independently print a date on java side initialized with new Date(), it also display correct date as of the system.
Now conversion part: on flex it was
25/04/2013 12:30 PM (as Alert displayed)
when i print this passed date(at java side), its
25/04/2013 02:30 PM (2 hours difference)
I have read many blogs etc for the solution, they refer it a time zone issue, but i didnt get it, if client and server are both on single system, how could time zone issue causes this problem.
Alert(flex) and println(java) with new Date() display correct date as of the system, so how that timezone issue comes in. only i can think of is, BlazeDS is causing this issue.
Here in this link they have refered some custom marshling for blazeDS but it went above my head
Custom Marshalling from Java to Flex via BlazeDS
Right now i have only one solution for this problem to send date in String as plain text instead of Date object and convert String back to Date object on java side.
Is there any better solution or if there is any issue with my understanding can someone please point out that.
Thanks,

I suggest the following solution.
First, send client timezone offset and store it as a session attribute.
Flex
ro.setClientTimezoneOffset(-new Date().getTimezoneOffset() * 60 * 1000);
Java
public void setClientTimezoneOffset(Long t) {
FlexContext.getFlexSession().setAttribute("clientTimezoneOffset", t);
}
Create our own endpoint class extending flex.messaging.endpoints.AMFEndpoint and point it at channel definition:
services-config.xml
<channel-definition id="my-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
class="com.package.AMFEndpoint"/>
</channel-definition>
AMFEndpoint.java
package com.package;
public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {
#Override
protected String getSerializerClassName() {
return Serializer.class.getName();
}
#Override
protected String getDeserializerClassName() {
return Deserializer.class.getName();
}
}
Extend amf serializer, deserializer, amf input/output:
Serializer.java
package com.package;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;
import java.io.OutputStream;
public class Serializer extends AmfMessageSerializer {
#Override
public void initialize(SerializationContext context, OutputStream out, AmfTrace trace) {
amfOut = new AMF0Output(context);
amfOut.setOutputStream(out);
amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);
debugTrace = trace;
isDebug = trace != null;
amfOut.setDebugTrace(debugTrace);
}
}
Deserializer.java
package com.package;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageDeserializer;
import flex.messaging.io.amf.AmfTrace;
import java.io.InputStream;
public class Deserializer extends AmfMessageDeserializer {
#Override
public void initialize(SerializationContext context, InputStream in, AmfTrace trace) {
amfIn = new AMF0Input(context);
amfIn.setInputStream(in);
debugTrace = trace;
isDebug = debugTrace != null;
amfIn.setDebugTrace(debugTrace);
}
}
AMF0Input.java
package com.package;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf0Input;
import java.io.IOException;
public class AMF0Input extends Amf0Input {
public AMF0Input(SerializationContext context) {
super(context);
}
#Override
public Object readObject() throws ClassNotFoundException, IOException {
if (avmPlusInput == null) {
avmPlusInput = new AMF3Input(context);
avmPlusInput.setDebugTrace(trace);
avmPlusInput.setInputStream(in);
}
return super.readObject();
}
}
AMF0Output.java
package com.package;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf0Output;
public class AMF0Output extends Amf0Output {
public AMF0Output(SerializationContext context) {
super(context);
}
#Override
protected void createAMF3Output()
{
avmPlusOutput = new AMF3Output(context);
avmPlusOutput.setOutputStream(out);
avmPlusOutput.setDebugTrace(trace);
}
}
And finally you extend amf 3 input/output classes, where date is serialized and deserialized. You apply offset difference.
AMF3Input.java
package com.package;
import flex.messaging.FlexContext;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import java.io.IOException;
import java.util.Date;
public class AMF3Input extends Amf3Input {
#Override
protected Date readDate() throws IOException {
Date d = super.readDate();
if (d != null) {
Long clientOffset = (Long) FlexContext.getFlexSession().getAttribute("clientTimezoneOffset");
Long serverOffset = (Long) (-d.getTimezoneOffset() * 60L * 1000);
d.setTime(d.getTime() - (serverOffset - clientOffset));
}
return d;
}
public AMF3Input(SerializationContext context) {
super(context);
}
}
AMF3Output.java
package com.package;
import flex.messaging.FlexContext;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Output;
import java.io.IOException;
import java.util.Date;
public class AMF3Output extends Amf3Output {
public AMF3Output(SerializationContext context) {
super(context);
}
#Override
protected void writeAMFDate(Date d) throws IOException {
if (d != null) {
Long clientOffset = (Long) FlexContext.getFlexSession().getAttribute("clientTimezoneOffset");
Long serverOffset = (Long) (-d.getTimezoneOffset() * 60L * 1000);
d.setTime(d.getTime() + (serverOffset - clientOffset));
}
super.writeAMFDate(d);
}
}
Now all dates, passed between Flex front-end and BlazeDS back-end will be automatically converted. Note, that you actually change the date.
Assume server time zone is GMT+6, and client is in GMT+2 timezome.
You're retrieving date from database. The date on java is 01.01.2013 10.00.00 GMT+6, normally flex would get 01.01.2013 06.00.00 GMT+2. It's the same date, but String equivalent differs. In our case flex will get 01.01.2013 10.00.00 GMT+2. We changed the date. But string equivalent is the same.

In addition create another class for compatibility with previous versions of Java:
package br.com.ultreia.flex;
import java.io.OutputStream;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfTrace;
public class Java15AmfMessageSerializer extends flex.messaging.io.amf.Java15AmfMessageSerializer{
#Override
public void initialize(SerializationContext context, OutputStream out, AmfTrace trace) {
amfOut = new AMF0Output(context);
amfOut.setOutputStream(out);
amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);
debugTrace = trace;
isDebug = trace != null;
amfOut.setDebugTrace(debugTrace);
}
}
And I changed the class AMFEndpoint.java
public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {
public AMFEndpoint(){
super();
}
#Override
protected String getSerializerClassName() {
return Serializer.class.getName();
}
#Override
protected String getSerializerJava15ClassName() {
return Java15AmfMessageSerializer.class.getName();
}
#Override
protected String getDeserializerClassName() {
return Deserializer.class.getName();
}
}

Related

sharing store data between extensions in JUNIT5

Is there anyway we can share data between different extensions in JUNIT 5 using store
Example
public class Extension1{
beforeAllCallback(){
getStore(GLOBAL).put(projectId,"112");
}
}
public class Extension2{
beforeTestExecutionCallback(){
System.out.println("projectId="+getStore(GLOBAL).get(projectId));
}
}
Yes, two extensions can share state via the Store as follows.
Note, however, that you may wish to store the shared state in the root context Store if you want the state to be accessible across test classes.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
#ExtendWith({ Extension1.class, Extension2.class })
public class Tests {
#Test
void test() {
// executing this results in the following being printed to SYS_OUT.
// PROJECT_ID=112
}
}
class Extension1 implements BeforeAllCallback {
public static final String PROJECT_ID = Extension1.class.getName() + ".PROJECT_ID";
#Override
public void beforeAll(ExtensionContext context) throws Exception {
context.getStore(Namespace.GLOBAL).put(PROJECT_ID, "112");
}
}
class Extension2 implements BeforeTestExecutionCallback {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
System.out.println("PROJECT_ID=" + context.getStore(Namespace.GLOBAL).get(Extension1.PROJECT_ID));
}
}

Android Restlet Returning no JSON data

I am creating a webserver on my Android device, and everything seems to be working fine except for the fact Jackson is not converting my objects to JSON. When I make a successfull (200) HTTP request from the browser on my Android device I am getting no JSON data in the network tab (Looking at the response in Google Chrome). I have registered the Jackson Converter as the documents state, and as what previous StackOverflow questions have covered. This does not seem to work, and I'm not getting any error. Any idea what I'm doing wrong? I hope this is enough information for you geniuses here, otherwise let me know what else you guys need.
Note I also tried GSONConverter
Edit: I've noticed that the entity inside the response is always null
WebServer.java
package com.android.restlettest;
import org.restlet.Component;
import org.restlet.data.Protocol;
public class WebServer {
Component component;
WebServer() {
component = new Component();
component.getServers().add(Protocol.HTTP, 9001);
component.getDefaultHost().attach("", new MyApplication());
}
void start() {
try {
System.out.println("Starting the WebServer");
component.start();
} catch(Exception e) {
System.out.println("Exception caught: " + e);
}
}
void stop() {
}
}
MyApplication.java
package com.android.restlettest;
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;
import org.restlet.engine.Engine;
import org.restlet.ext.gson.GsonConverter;
import org.restlet.ext.jackson.JacksonConverter;
public class MyApplication extends Application {
MyApplication() {
super();
Engine.getInstance().getRegisteredConverters().add(new JacksonConverter());
//Engine.getInstance().getRegisteredConverters().add(new GsonConverter());
}
#Override
public synchronized Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/", IndexResource.class);
router.attach("/report/log", LogServerResource.class);
return router;
}
}
LogServerResource.java
public class LogServerResource extends ServerResource implements ILogResource {
#Get("json")
public Log retrieve() {
Log[] list = new Log[2];
Log log1 = new Log("test.log", "alksdjf32984u23jfsdv", 0);
list[0] = log1;
return list[0];
//return "{\"resource\": \"log\"}";
}
}
Log.java
package com.android.restlettest;
import java.io.Serializable;
public class Log implements Serializable {
private static final long serialVersionUID = 1L;
public String data;
public String name;
public int id;
public Log() {
}
public Log(final String name, final String data, final int id) {
super();
this.name = name;
this.data = data;
this.id = id;
}
}
I ended up finding someone that had a similar issue to me. I was missing some libs that needed to be added. I apologize for wasting your time.
Restlet server on Android: client is getting a null object

jackson serialize different time zones into single time zone

I have multiple timezones and I want to have them exactly after serialization, but jackson convert them into single time zone if I set DateFormat all zones convert to context time zone and if I don't set DateFormat all zones convert to UTC (zero time zone).
I know that we have DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE in deserialization and we can disable it but I can't find something like this in SerializationFeature.
Is there anyway that I can tell jackson to don't convert timezones?
here is my test class:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class Test {
public static class flight {
private XMLGregorianCalendar dateDeparture;
private XMLGregorianCalendar dateArrival;
public XMLGregorianCalendar getDateDeparture() {
return dateDeparture;
}
public void setDateDeparture(XMLGregorianCalendar dateDeparture) {
this.dateDeparture = dateDeparture;
}
public XMLGregorianCalendar getDateArrival() {
return dateArrival;
}
public void setDateArrival(XMLGregorianCalendar dateArrival) {
this.dateArrival = dateArrival;
}
}
public static void main(String[] args) throws DatatypeConfigurationException, JsonProcessingException {
XMLGregorianCalendar dateDeparture = DatatypeFactory.newInstance().newXMLGregorianCalendar(2018,1,22,10,15,0,0, TimeZone.getTimeZone("Asia/Istanbul").getRawOffset()/1000/60);
XMLGregorianCalendar dateArrival = DatatypeFactory.newInstance().newXMLGregorianCalendar(2018,1,22,13,30,0,0,TimeZone.getTimeZone("Asia/Dubai").getRawOffset()/1000/60);
System.out.println("Local Departure Time=" + dateDeparture);
System.out.println("Local Arrival Time=" + dateArrival);
flight flight = new flight();
flight.setDateDeparture(dateDeparture);
flight.setDateArrival(dateArrival);
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
xmlMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ"));
String xml = xmlMapper.writeValueAsString(flight);
System.out.println(xml);
}
}
here is the output:
Local Departure Time=2018-01-22T10:15:00.000+03:00
Local Arrival Time=2018-01-22T13:30:00.000+04:00
<flight><dateDeparture>2018-01-22T10:45:00+0330</dateDeparture><dateArrival>2018-01-22T01:00:00+0330</dateArrival></flight>
The only way I could think of is to create your own serialize module so to be able to handle XMLGregorianCalendar serialization all by yourself. Unfortunately Java has proven not to be good in handling dates.
public class XMLCalendarSerializer extends StdSerializer<XMLGregorianCalendar> {
public XMLCalendarSerializer() {
this((Class)null);
}
public XMLCalendarSerializer(Class<XMLGregorianCalendar> t) {
super(t);
}
public void serialize(XMLGregorianCalendar value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
DateFormat dateFormatt = provider.getConfig().getDateFormat();
if(dateFormatt.getCalendar() == null) {
jgen.writeString(value.toString());
} else {
SimpleDateFormat dateFormat = (SimpleDateFormat)dateFormatt;
GregorianCalendar a = value.toGregorianCalendar();
Date date = value.toGregorianCalendar().getTime();
dateFormat.setTimeZone(TimeZone.getTimeZone(value.getTimeZone(value.getTimezone()).getDisplayName()));
jgen.writeString(dateFormat.format(date));
}
}
}
and the module class would be like:
public class XMLCalendarModule extends SimpleModule {
private static final String NAME = "CustomXMLCalendarModule";
private static final VersionUtil VERSION_UTIL = new VersionUtil() {
};
public XMLCalendarModule() {
super("CustomXMLCalendarModule", VERSION_UTIL.version());
this.addSerializer(XMLGregorianCalendar.class, new XMLCalendarSerializer());
}
}
and you can simply register this module like:
xmlMapper.registerModule(new XMLCalendarModule());

OnTurnBasedMatchUpdateReceivedListener does not trigger

I am trying to get the OnTurnBasedMatchUpdateReceivedListener to trigger but it doesn't seem to work. Below is my code example that I am using. I get a valid GoogleApiClient and am already signed in (I have other Listeners going in other parts of code).
The goal is to have a single class that can handle this event, by passing the GoogleApiClient through and have it callback here (I have no other way of getting code to trigger such as the BaseGameActivity because the code is within another LIB and I am writing additional code).
Any suggestions on how to debug this?
package com.google.example.games.pluginsupport;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.games.Games;
import com.google.android.gms.games.multiplayer.turnbased.OnTurnBasedMatchUpdateReceivedListener;
import com.google.android.gms.games.multiplayer.turnbased.TurnBasedMatch;
public class TurnBaseMatchHelper implements OnTurnBasedMatchUpdateReceivedListener {
public interface TurnBasedMatchListener {
void onTurnBasedMatchReceived(TurnBasedMatch match);
void onTurnBasedMatchRemoved(String matchId);
}
private static TurnBaseMatchHelper turnbaseInterface = null;
private TurnBasedMatchListener sTurnBasedMatchListener = null;
public static void registerTurnBasedCallbacks(GoogleApiClient _googleApiClient, TurnBasedMatchListener sListener) {
if (turnbaseInterface == null) {
turnbaseInterface = new TurnBaseMatchHelper();
}
turnbaseInterface.sTurnBasedMatchListener = sListener;
Log.d("Unity", "registerTurnBasedCallbacks");
Games.TurnBasedMultiplayer.registerMatchUpdateListener(_googleApiClient, turnbaseInterface);
}
#Override
public void onTurnBasedMatchReceived(TurnBasedMatch match) {
Log.d("Unity", "onTurnBasedMatchReceived");
if (turnbaseInterface.sTurnBasedMatchListener != null) {
sTurnBasedMatchListener.onTurnBasedMatchReceived(match);
}
}
#Override
public void onTurnBasedMatchRemoved(String matchId) {
Log.d("Unity", "onTurnBasedMatchRemoved");
if (turnbaseInterface.sTurnBasedMatchListener != null) {
sTurnBasedMatchListener.onTurnBasedMatchRemoved(matchId);
}
}
}
here is my similar problem answer.
From post:
Go to the Settings -> Account and sync-> turn on Auto-sync checkbox

How do you serialize Guava's immutable collections using Protostuff?

I use protostuff-runtime to serialize object graphs. Some of these objects have reference to Guava immutable collections, such as ImmutableList and ImmutableSet. Protostuff is unable to deserialize these collections out of the box, because it tries to construct an instance and then "add" elements to it from the inputStream (which fails, since the collections are immutable).
Do you know of any library / protostuff plugin that does that out of the box? If not, is there a best practice to do this myself?
I've investigated, and found that protostuff has a concept of "delegate", that lets you take control of the serialization for specific types. It seems to be the answer to my problem, but I can't seem to get it working.
Here is what I have right now:
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* This is the POJO I want to serialize. Note that the {#code strings} field refers to an {#link ImmutableList}.
*/
#Immutable
public class Foo {
public static final Schema<Foo> SCHEMA = RuntimeSchema.getSchema(Foo.class);
#Nonnull
private final ImmutableList<String> strings;
public Foo(ImmutableList<String> strings) {
this.strings = Preconditions.checkNotNull(strings);
}
#Nonnull
public ImmutableList<String> getStrings() {
return strings;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Foo) {
Foo that = (Foo) obj;
return this.strings.equals(that.strings);
}
return false;
}
#Override
public int hashCode() {
return strings.hashCode();
}
}
import com.dyuproject.protostuff.*;
import com.dyuproject.protostuff.runtime.Delegate;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.ArrayList;
public class ImmutableListDelegate implements Delegate<ImmutableList<?>> {
private static final Schema<ArrayList> LIST_SCHEMA = RuntimeSchema.getSchema(ArrayList.class);
#Override
public WireFormat.FieldType getFieldType() {
return WireFormat.FieldType.MESSAGE;
}
#Override
public ImmutableList<?> readFrom(Input input) throws IOException {
ArrayList<?> list = LIST_SCHEMA.newMessage();
input.mergeObject(list, LIST_SCHEMA);
return ImmutableList.copyOf(list);
}
#Override
public void writeTo(Output output, int number, ImmutableList<?> value, boolean repeated) throws IOException {
ArrayList<?> list = Lists.newArrayList(value);
output.writeObject(number, list, LIST_SCHEMA, repeated);
LIST_SCHEMA.writeTo(output, list);
}
#Override
public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated) throws IOException {
throw new UnsupportedOperationException("TODO");
}
#Override
public Class<?> typeClass() {
return ImmutableList.class;
}
}
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.runtime.DefaultIdStrategy;
import com.dyuproject.protostuff.runtime.RuntimeEnv;
import com.google.common.collect.ImmutableList;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ImmutableListDelegateTest {
#Before
public void before() {
// registers the delegate
if (RuntimeEnv.ID_STRATEGY instanceof DefaultIdStrategy) {
((DefaultIdStrategy) RuntimeEnv.ID_STRATEGY).registerDelegate(new ImmutableListDelegate());
}
}
#Test
public void testDelegate() throws IOException {
Foo foo = new Foo(ImmutableList.of("foo"));
Assert.assertEquals(foo, serializeThenDeserialize(foo));
}
private Foo serializeThenDeserialize(Foo fooToSerialize) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ProtostuffIOUtil.writeDelimitedTo(out, fooToSerialize, Foo.SCHEMA, buffer());
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
Foo fooDeserialized = Foo.SCHEMA.newMessage();
ProtostuffIOUtil.mergeDelimitedFrom(in, fooDeserialized, Foo.SCHEMA, buffer());
return fooDeserialized;
}
private LinkedBuffer buffer() {
return LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
}
}
The test fails with the following exception, which seems to mean that my delegate only deserializes null values:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191)
at com.google.common.collect.SingletonImmutableList.<init>(SingletonImmutableList.java:40)
at com.google.common.collect.ImmutableList.asImmutableList(ImmutableList.java:305)
at com.google.common.collect.ImmutableList.copyFromCollection(ImmutableList.java:314)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:253)
at test.ImmutableListDelegate.readFrom(ImmutableListDelegate.java:25)
at test.ImmutableListDelegate.readFrom(ImmutableListDelegate.java:12)
at com.dyuproject.protostuff.runtime.RuntimeUnsafeFieldFactory$19$1.mergeFrom(RuntimeUnsafeFieldFactory.java:1111)
at com.dyuproject.protostuff.runtime.MappedSchema.mergeFrom(MappedSchema.java:188)
at com.dyuproject.protostuff.IOUtil.mergeDelimitedFrom(IOUtil.java:109)
at com.dyuproject.protostuff.ProtostuffIOUtil.mergeDelimitedFrom(ProtostuffIOUtil.java:151)
at test.ImmutableListDelegateTest.serializeThenDeserialize(ImmutableListDelegateTest.java:38)
at test.ImmutableListDelegateTest.testDelegate(ImmutableListDelegateTest.java:30)
Is this the right approach? What am I missing?
This is not a duplicate of the What is a Null Pointer Exception, and how do I fix it? question, which makes no sense. The fact that I mentioned that an NPE is thrown when trying to use a Protostuff delegate to de-serialize immutable collections, doesn't mean that this duplicates the "What is a NPE?" question in any way, shape, or form.
Everything looks fine and the
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191)
at com.google.common.collect.SingletonImmutableList.<init>(SingletonImmutableList.java:40)
says that you're trying to put null into an ImmutableList, which is forbidden. To be sure, inspect you list just before the failing line. Make sure your input json doesn't look like [null].

Categories