jackson mini json to object class - json

I was added "jackson-mini-1.9.2.jar"(is not "jackson-all-1.9.2.jar") in my project,
I want to convert json to object class.
Use "jackson-all-1.9.2.jar",we can use "ObjectMapper" to get it.
but use "jackson-mini-1.9.2.jar",How to do it?
If I write the follow code"
String json = "{\"name\" : {\"first\" : \"Joe\", \"last\" : \"Sixpack\" }, \"gender\" : \"MALE\", \"verified\" : false, \"userImage\" : \"Rm9vYmFyIQ==\" }";
JsonFactory f = new JsonFactory();
JsonParser jp = f.createJsonParser(json);
User user = jp.readValueAs(User.class);
The result is like that:
Exception in thread "main" java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into Java objects
at org.codehaus.jackson.JsonParser.readValueAs(Unknown Source)
at TestJackson.main(TestJackson.java:21)

You can implement your own ObjectCodec and then register it with the JsonFactory by calling JsonFactory#setCodec(myCodec).
Or (much easier!), just get hold of jackson-mapper-1.9.2.jar and add it to your classpath, so that you can use the default ObjectMapper.

If you want to use data-binding, do NOT use mini jar. It is only meant as the smallest possible jar to use Streaming Parsing (JsonParser, JsonGenerator).

Related

Corda query throws "com.fasterxml.jackson.databind.JsonMappingException: object is not an instance of declaring class"

I'm developing cordapp using the example-cordapp project as a reference. I've been able to commit a transaction to the ledger and even run querias on the node to see if it's really there. However, when I try to run query from my Spring Boot application, I get this error.
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request
processing failed; nested exception is
org.springframework.http.converter.HttpMessageConversionException: JSON mapping problem:
java.util.Collections$UnmodifiableRandomAccessList[0]->net.corda.core.contracts.StateAndRef["state"]-
>net.corda.core.contracts.TransactionState["data"]-
>com.mypackage.states.MyState["party"]; nested exception is
com.fasterxml.jackson.databind.JsonMappingException: object is not an instance of declaring class
(through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]-
>net.corda.core.contracts.StateAndRef["state"]->net.corda.core.contracts.TransactionState["data"]-
>com.mypackage.states.MyState["party"])] with root cause
java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_251]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~
[na:1.8.0_251]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_251]
Here's the request code
#GetMapping(value = [ "/api/v1/states" ], produces = [MediaType.APPLICATION_JSON_VALUE])
fun getMyIOUs(): ResponseEntity<List<StateAndRef<MyState>>> {
val myStates = proxy.vaultQueryBy<MyState>().states
return ResponseEntity.ok(myStates)
}
And here's the state code
#BelongsToContract(com.sentinel.contract.SharingInformationContract::class)
class SharingInformationState(
val party: Party,
val dataOwnerId: Long,
val dataBuyerId: Long,
override val linearId: UniqueIdentifier = UniqueIdentifier()) : LinearState, QueryableState {
override val participants: List<AbstractParty> = listOf(party)
override fun generateMappedObject(schema: MappedSchema): PersistentState {
return when (schema) {
SharingInformationSchemaV1 -> SharingInformationSchemaV1.PersistentSharingInformation(
party,
dataOwnerId,
dataBuyerId,
linearId.id
)
else -> throw IllegalArgumentException("Unrecognised schema $schema")
}
}
override fun supportedSchemas(): Iterable<MappedSchema> = listOf(SharingInformationSchemaV1)
}
There's little information about this issue on the internet. Some suggest it is connected to the classpath, that something is duplicated there, but I don't know how to check. Also, this error isn't connected to the Party type. I've tried to add #JsonIgnore on a party, but then it throws on the other field. Persistence of this field in mapping schema also doesn't matter. I've tried persisting and not persisting, it changes nothing. Thanks in advance!
I believe this is because you are missing Corda Jackson support library which is required to convert Corda objects to json.
Add this to your dependencies in the build.gradle
compile "net.corda:corda-jackson:$corda_release_version"
https://github.com/corda/samples-java/blob/master/Advanced/auction-cordapp/client/build.gradle#L19
Also, make sure you have a MappingJackson2HttpMessageConverter bean configured.
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
ObjectMapper mapper = JacksonSupport.createDefaultMapper(partyAProxy());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(mapper);
return converter;
}
https://github.com/corda/samples-java/blob/master/Advanced/auction-cordapp/client/src/main/java/net/corda/samples/client/AppConfig.java#L48
The Exception java.lang.IllegalArgumentException: object is not an instance of declaring class is something that happens if a method is called by reflection on an object which is of the wrong type.
In conjunction with jackson that may happen because a generic is lying to you. Here is an example:
class A (val x: String)
class B (val y: String)
class C (val z: List<A>)
ObjectMapper().writeValueAsString(C(listOf(B("x")) as List<A>))
This causes a compile warning, but it compiles and initially runs because of type erasure. However we forcefully injected a List<B> in a place where actually a List<A> is expected. While type erasure does remove quite a bit of information, it does not do so completely. Reflection can still be used to determine that C.z is actually of type List<A>. Jackson uses this information and tries to serialize an object of type A but instead finds an object of type B in the list and fails with the given message.
Check that your data structure actually contains the types that you expect!

Why I parse json into a Java List, but not a Scala List?

I am attempting to parse a json object that contains a list. I am able to parse the list if the field is backed by a Java List, but it fails if the field is backed by a Scala list. What is the difference between parsing into a Scala List vs a Java List, and what do I have to change to be able to parse this into a Scala List?
object JsonParsingExample extends App {
val objectMapper = new ObjectMapper()
// This line succeeds.
objectMapper.readValue("""{"list": ["a","b"]}""", classOf[JavaList])
// This line fails.
objectMapper.readValue("""{"list": ["a","b"]}""", classOf[ScalaList])
}
case class JavaList() {
#JsonProperty(value = "list")
var myList: java.util.ArrayList[String] = null
}
case class ScalaList() {
#JsonProperty(value = "list")
var myList: List[String] = null
}
The error message I receive is:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of scala.collection.immutable.List, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
Jackson doesn't know anything about Scala types by default (otherwise it would have to depend on scala-library). To teach it, use jackson-module-scala.
Because the scala.collection.immutable.List is actually an abstract class. Generally when you use List("a", "b", "c") is the object List.apply() which is coming from this line: https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/immutable/List.scala#L452 and that's actually an inner class (something called scala.collection.immutable.$colon$colon).

How to get spring RestTemplate, scala and jackson to play nice to together

I seem to be able to use Jackson to make a mapper of Json-String --> scala.collection.Map.
How can I hook up that same mapper to a RestTemplate?
val restTemplate = new RestTemplate()
val module = new OptionModule with MapModule with SeqModule with IteratorModule
val mapper = new ObjectMapper()
mapper.registerModule(module)
// Get some example JSON
val uri = "http://...."
val response:String = restTemplate.getForObject(uri, classOf[String] )
// *** success ***
// Use the mapper directly: String --> scala.collection.Map
val map1 = mapper.readValue(response, classOf[scala.collection.Map[String, Any]])
// Try hooking up the same module to the RestTemplate:
val wrappingConverter = new WrappingHttpMessageConverter()
wrappingConverter.getObjectMapper().registerModule(module)
val list = restTemplate.getMessageConverters()
list.add(wrappingConverter)
restTemplate.setMessageConverters(list)
// *** FAILS ***
// org.springframework.http.converter.HttpMessageNotReadableException: Could not read
// JSON: Can not construct instance of scala.collection.Map, problem: abstract types
// either need to be mapped to concrete types, have custom deserializer, or be
// instantiated with additional type information
val map2 = restTemplate.getForObject(uri, classOf[scala.collection.Map[String, Any]] )
Assumtions
WrappingHttpMessageConverter is a derived class of MappingJackson2HttpMessageConverter, or some class that works like it.
You're using Spring 4.0 (though this answer is probably also true for Spring 3.2)
The problem
The default RestTemplate constructor tries to detect if Jackson is on your classpath, and if it is, adds MappingJackson2HttpMessageConverter to the MessageConverters list. Since it's already on the list, it's going to be used before your WrappingHttpMessageConverter is ever checked.
That default converter doesn't have the Scala module installed. Here's where things get tricky. HttpMessageConverterExtractor tries to ask if the first converter can deserialize the type; currently ObjectMapper returns true for this test (whether it should is a much longer topic, not as clear cut as it might seem). The extractor doesn't handle the idea that one converter could fail, but a later one might succeed (as it would in your case).
Workarounds
You need to make sure that Spring finds an ObjectMapper configured with the Scala module before it tries with any other. You can do this in a number of ways; the most robust is to search the preconfigured converters and update the first you find, adding a new one if you don't find any:
val jacksonConverter = list.asScala.collectFirst {
case p: MappingJackson2HttpMessageConverter => p
}
if (jacksonConverter.isDefined) {
jacksonConverter.get.getObjectMapper.registerModule(module)
}
else {
list.add(new MappingJackson2HttpMessageConverter) // or your derived class if you prefer
}
Other options include adding your custom message converter to the front of the list, or removing the existing Jackson converter before adding your own.

deserialize lazylist using jackson

I have a object which uses a org.apache.commons.collections.list.LazyList for one of its fields, which is serialized ti JSON. The JSON looks like this:
"myObject": ["org.apache.commons.collections.list.LazyList", [
{
"attr1": "asdasd",
"attr2": 1234
}
]],
The object field looks like this:
List<MyObject> myObject = ListUtils.lazyList(new ArrayList(), {new MyObject()} as Factory)
However trying to deserialize the above JSON using a Jackson ObjectMapper fails, since it can't find a default constructor for a LazyList - which makes sense. But how can I specify how this field can be deserialized?
Error message:
No default constructor for [collection type; class org.apache.commons.collections.list.LazyList, contains [simple type, class foo.bar.MyObject]]
Bounty-constraints:
To collect the bounty, this question needs to be answered using a custom jackson deserializer - the custom deserializer must not be field specific! Hence no solution using custom implementations of a LazyList for a specific type will answer this question adequately.
The solution below worked on both List and Map collection objects, it might also work on yours.
#JsonDeserialize(contentAs=MyObject.class)
private List<MyObject> myObject = ListUtils.lazyList(new ArrayList(), {new MyObject()} as Factory);

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy

I'm using a Restful web service (Jersy implementation) with a JSF application and used Json to get the data as follows:
carObjectDao = new GenericDAO<carObject>(carObject.class);
List<carObject> allCars = carObjectDao.readAll();
Gson gson = new Gson();
String carString = gson.toJson(allCars);
System.err.println(carString );
return carString ;
i run the application in debug mode and allCars is filled with the data correctly, but after that an exception is thrown :
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?
i don't know the root cause of the exception
This is a known problem: Could not serialize object cause of HibernateProxy
JSon can't deserialize HibernateProxy objects, so you either unproxy or remove em.
Or, you can eager fetch the lazy data.
Try parsing through ObjectMapper as
carObjectDao = new GenericDAO<carObject>(carObject.class);
List<carObject> allCars = carObjectDao.readAll();
String carString = new ObjectMapper().writeValueAsString(allCars);
System.err.println(carString );
return carString ;