Unmarshal JSON to Map/List of Strings - json

I would like to unmarshal a Json to a Map/List of Strings (eg Map>...)
Here is my input:
{"pointsOfSale":
{"pointOfSale":[
{"href":"\/pointsOfSale\/UUID.0abc2aca-7930-4c9e-9f38-8af3d0692e04",
"model":{"href":"\/models\/modelePointOfSale",
"modelType":{"href":"\/modelTypes\/pointOfSale"}},
"source":{"href":"\/sources\/TEST"},
"attribute":[
{"code":"pointOfSalePhysical","value":true},
{"code":"mail","value":"Mail1"},
{"code":"adresse","value":"address1"}]},
{"href":"\/pointsOfSale\/UUID.a12e7adf-652a-4197-91bf-d4785e43f09f",
"model":{"href":"\/models\/modelePointOfSale",
"modelType":{"href":"\/modelTypes\/pointOfSale"}},
"source":{"href":"\/sources\/Wikeo"},
"attribute":[
{"code":"pointOfSalePhysical","value":false},
{"code":"mail","value":"Mail1"},
{"code":"adresseMateriau","value":"Material address1"}]}
}}
I would like to be able to do "something" like this after unmarshaling:
myJsonMapped.get("pointsOfSale").get("pointOfSale").get(0).get("source").get("href").equals("\/sources\/TEST") == true
For instance, with Gson we can do this kind of decoding:
new Gson().fromJson(json, Map.class);
I know I can do this with a simple bean or processor etc...
I just want to know of I can do this more efficiently with a native JSON camel component config
EDIT: I tried different thing already like :
unmarshal().json()...
or
unmarshal().json(JsonLibrary.Gson, Map.class)..
etc...
without succes :'(

You could do something like this with jackson.
<dataFormats>
<json id="jack" library="Jackson"/>
</dataFormats>
...
<route>
<from uri="direct:test"/>
<unmarshal ref="jack"/>
<process ref="something"/>
</route>
Or in java with gson:
from("foo:bar")
.unmarshal().json(JsonLibrary.Gson,Map.class)
.to("foo:baz");
If you're not getting it to work, please state error and so fourth.

Related

Parsing json with dynamic types in scala with lift-json

I'm trying to write a JSON parse using lift-web and scala. I mapped my JSON to several case classes (for nested values/types), but I'm stuck with a MappingException error. This is the nested part of the JSON i'm trying to parse:
...
"attachments":[{"8a7d22ff":"Image1.png"}],
...
for which I specified the following parameter in the case class
case class myType(
...
attachments: List[(String,String)]
...
)
Unfortunately, I got this message:
Caused by: net.liftweb.json.MappingException: Expected collection but got JObject(List(JField(8a7d22ff,JString(Image1.png)))) for root JObject(List(JField(8a7d22ff,JString(Image1.png)))) and mapping Constructor(TypeInfo(class scala.Tuple2,Some(class scala.Tuple2[class java.lang.String,class java.lang.String])),List(DeclaredConstructor(public scala.Tuple2(java.lang.Object,java.lang.Object),List(Arg(_1,Value(class java.lang.String),false), Arg(_2,Value(class java.lang.String),false)))))
at net.liftweb.json.Meta$.fail(Meta.scala:227)
at net.liftweb.json.Extraction$.newCollection$1(Extraction.scala:330)
at net.liftweb.json.Extraction$.build$1(Extraction.scala:400)
at net.liftweb.json.Extraction$.mkValue$1(Extraction.scala:431)
... 30 more
I also tried Map[String,String] but nothing, I do not really understand which datatype I've to put for parsing JSON with dynamic types...Any idea?

I can't parse a JSON with gson

i have this part of my json
POKEAPI get pokemons/sprite/version/
is from POKEAPI, the problem is in kotlin I can't use the '-' for creating a variable, for example: "var myvar-i = 0" and I need to create the variables exactly like the JSON for GSON mapping and the sprites in the JSON I need are like this
generation-i
generation-ii
etc..
in kotlin, I can't create variables with the '-'
enter image description here
someone help me, ¿How can I map that information in kotlin?
You can use the annotation #SerializedName
In your case it would be something like:
class Versions {
#SerializedName("generation-i")
var generation1: Generationgame? = null
...
}
More about the annotation can be found in the docs.

API Logging in Json format

I would like to log API request/response as json format.
The expected LogEntry is something like
{
"timestamp" : "...",
"level" : "DEBUG",
"headers" : [
"header1" : "value1",
"header2" : "value2",
"header3" : "value3"
],
"requestPayload" : "<Request Json>" // prefereablly as sub-document, worst case string is fine.
"labels" : [ //key fields which can be used for searching the logentry
"searchField1" : "....",
"searchField2" : "....",
"searchField3" : "...."
]
}
My Question is :
Using Logback, How to log nested fields (e.g. headers, labels, requestPaylod in above example), as json sub-document. I tried MDC, but its limited to
Map of 'String, String' only, and considers all fields after first level as String.
I hate to write my custom logger for this, and would like to use the goodness of proven logging frameworks(logback/log4j) to control the logging level, time stamping log event, etc.
For request/response logging try Logbook and logstash-logback-encoder. You'll be able to use Markers to add structured contents.
For adding 'your own' fields in a JSON structure, I've written a code generator you might find interesting, it adds builder support: json-log-domain
You can use logback-contrib's JsonLayout inside any Logback appender. For example:
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
<prettyPrint>false</prettyPrint>
</jsonFormatter>
<timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
<appendLineSeparator>true</appendLineSeparator>
</layout>
</appender>
Given log statements like this ...
MDC.put("header1", "headerValue1");
logger.info("hello!");
logger.info("good bye!");
... the use of JsonLayout would result in Logback writing this:
{"timestamp":"2017-08-15 09:06:41.813","level":"INFO","thread":"main","mdc":{"header1":"headerValue1"},"logger":"com.stackoverflow.logback.LogbackTest","message":"hello!","context":"default"}
{"timestamp":"2017-08-15 09:06:41.887","level":"INFO","thread":"main","mdc":{"header1":"headerValue1"},"logger":"com.stackoverflow.logback.LogbackTest","message":"good bye!","context":"default"}
I think this ticks the boxes of writing your log events as JSON documents whilst still retaining Logback's behaviour such as "control the logging level, time stamping log event, etc". There is some built-in support for changing the JSON format (e.g. you can include/exclude context, logger name etc) but the JsonLayout class provides an extension point which would allow you to change the attribute names in the resulting JSON by extending JsonLayout and overriding toJsonMap().
Edit 1: addressing your reply ("my question was more on how to achieve json subdocument/nesting as mentioned. MDC is limited to map of only") ... you could serialise your complex MDC values to JSON and add the serialised JSON representations to MDC. For example:
Map<String, Object> complexMdcValue = new HashMap<>();
Map<String, Object> childMdcValue = new HashMap<>();
childMdcValue.put("name", "Joe");
childMdcValue.put("type", "Martian");
complexMdcValue.put("child", childMdcValue);
complexMdcValue.put("category", "etc");
MDC.put("complexNestedValue", objectMapper.writeValueAsString(complexMdcValue));
logger.info("hello!");
Would produce this output (in which the MVC logged key "complexNestedValue" is JSON containing a sub document):
{"timestamp":"2017-08-27 18:03:46.706","level":"INFO","thread":"main","mdc":{"complexNestedValue":"{\"category\":\"etc\",\"child\":{\"name\":\"Joe\",\"type\":\"Martian\"}}"},"logger":"com.stackoverflow.logback.LogbackTest","message":"hello!","context":"default"}

Mule-How to convert payload into json

I have this:
{a=1, b=2, c=3}, {a2=1, b2=2, c2=3}, {a3=1, b3=2, c3=3},
I need an output of json like this:
[{"a":"1", "b":"2", "c":"3"}, {"a2":"1", "b2":"2", "c2":"3"}, {"a3":"1", "b3:2", "c3:3"}]
How to do so in Mule CE? Any Suggestions?
EDIT:
I have return data from magento <magento:list-products/>, and converted the payload like this:
<json:object-to-json-transformer doc:name="Object to JSON"/>
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object"/>
I had to do some filtering on that payload: used <foreach/> and for every product that fit the condition I saved in a variable like this:
<set-variable variableName="productsInfoArr"
value="#[flowVars.productsInfoArr.concat(flowVars.productInfo)+',']"/>
so the results are as above...
So basically the question is: how to create an array using json items?
I take it you payload is a Java Collection of Maps. If so, simply use the:
<json:object-to-json-transformer />
I usually use JSONArray to store the list of JSON object. In this case you might need to manipulate the input through Expression component:
<expression-component doc:name="Expression">
<![CDATA[
String input = payload.replaceAll("=", ":");
input = input.replaceAll(",$", "");
payload = new org.json.JSONArray("[" + input + "]");]]>
</expression-component>

Marshalling an empty collection to json using jersey

I have a strange issue marshalling an empty object collection to json using jersey with the jaxb based json support. My object looks like
...
#XmlWrapper(name = "stuff") #XmlElement(name = "s")
private List<Foo> foos;
...
Marshaling this to json produces the expected results
... stuff: [{ "s": ... }, { "s": ... }] ...
except when the list is empty. I would expect to see
... stuff: [] ...
but I see
... stuff: [null] ...
instead. Any idea what's wrong? The problem seems to be related to the #XmlElementWrapper annotation, removing it I don't get the the stuff property in the output at all.
Are you serializing an empty list, or are you serializing an un-instantiated null object?
ie. I would expect:
private List<Foo> foos; - would serialize to 'stuff: [null]'
and I would also expect:
private List<Foo> foos = new ArrayList<Foo>(); - we serialize to 'stuff: []'
If that isn't the case, you can always direct Jackson (which is the default JSON serializer bundled with Jersey) to omit the writing of bean properties as null value..
I would suggest using POJO mapping based on Jackson. I am not sure why you want that intermediate "s" in there, but POJO would produce (and consume) simpler structure:
"stuff" : [ { ... }, { ... } ]
For that you need no annotations with POJO mapping; JAXB annotations are only needed for XML processing, since XML has no natural mechanism to distinguish arrays from objects (unlike JSON).
I managed to solve JSON array and primitive field "bug" in Jersey json library. Secret ingredient is JSONConfiguration and ContextResolver magic. See my following post it has a full code example, customized ContextResolver and rest Application class might be somewhat fuzzy logic in first look.
How to serialize Java primitives using Jersey REST
json array for zero or single-element Java lists
primitive integer or boolean fields without quotation chars