I am trying to parse a JSON file using Jackson Json parser and in the process using the get(String nodename) function of it.
But when i have multiple nodes of the same name , it is trying to get to the last of the similar nodes and act only on them. How do i get to all the nodes.
For example if my json file was
{"menu":{"a":"1", "b":"2"},
"menu":{"c":"1", "d":"2"},
"menu":{"e":"1", "f":"2"}}
and if i'm trying to do a get("menu") and try to print the field names in it, only e and f get printed whereas i want a b c d e f to get printed.
I'd probably make use of #JsonAnySetter, along the following lines.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
public class App
{
public static void main(String[] args) throws Exception
{
/* {"menu":{"a":"1", "b":"2"},"menu":{"c":"1", "d":"2"},"menu":{"e":"1", "f":"2"}} */
String json = "{\"menu\":{\"a\":\"1\", \"b\":\"2\"},\"menu\":{\"c\":\"1\", \"d\":\"2\"},\"menu\":{\"e\":\"1\", \"f\":\"2\"}}";
ObjectMapper mapper = new ObjectMapper();
Foo foo = mapper.readValue(json, Foo.class);
System.out.println(foo.menus);
}
}
class Foo
{
List<Menu> menus = new ArrayList<>();
#JsonAnySetter
public void addMenu(String key, Menu menu)
{
menus.add(menu);
}
}
class Menu
{
Map<String, Object> items = new HashMap<> ();
#JsonAnySetter
public void addItems(String itemName, String itemValue)
{
items.put(itemName, itemValue);
}
#Override
public String toString()
{
return String.format("%s", items);
}
}
Related
I am trying json parsing with gson in a small java applicaiton. I have a json string which comes from .Net business layer, has a field as "1999-08-24T00:00:00". In my model like User model, I have java.time.Instant birthDay field. With gson i am trying to get json string to my user model. Also I have a InstantDeserializer class. But when I try to convert it I got a message like java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)..
Before the instant type I was using Date class. I wrote DateDeserializer class but I know Date class is deprecated. I googled to much page. I tried many things but i didn't how to figure out. So i just want to ask where I am making mistakes. What sould I do? How can I make my code more clear or what is the best approch? If you could give some code examples, I can understand better.
Any advice is appreciated..
Here is my code..
JSON String :
{
"Value":{
"ID":"123",
"NAME":"John",
"SURNAME":"Concept",
"BIRTHDAY":"1999-08-24T00:00:00",
"PAYMENTINFORMATION":[
{
"ID":"1",
"PAYMENTINFO":"RECIEVED"
}
]
},
"Succued": true
}
UserModel class
package Models;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.time.LocalDateTime;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
import java.time.Instant;
public class UserModel {
private long id;
private String name;
private String surname;
private Instant birthday;
private List<PaymentModel> paymentInformation;
//GETTER SETTER
public UserModel() {
paymentInformation= new ArrayList<>();
}
}
InstantDeserializer class
package Util;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class InstantDeSerializer implements JsonDeserializer<Instant> {
#Override
public Instant deserialize(JsonElement jelement, Type type, JsonDeserializationContext jdc) throws JsonParseException {
Instant insObj= Instant.ofEpochMilli(jelement.getAsJsonPrimitive().getAsLong());
return insObj;
}
}
And Main class
public class JSONTryMe {
public static void main(String[] args) throws Exception {
JSONObject responseJSON = new JSONObject(jsonString);
if (responseJSON.isNull("Value")) {
return;
}
GsonBuilder build = new GsonBuilder();
build.registerTypeAdapter(Instant.class, new InstantDeSerializer());
Gson gObj = build.create();
UserModel user = gObj.fromJson(responseJSON.getJSONObject("Value").toString(), UserModel.class);
System.out.println(user.getBirthday().toString());
}
}
Ant the error stackTrace is
java.lang.NumberFormatException: For input string: "1999-08-24T00:00:00"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.parseLong(Long.java:631)
at com.google.gson.JsonPrimitive.getAsLong(JsonPrimitive.java:206)
at Util.InstantDeSerializer.deserialize(InstantDeSerializer.java:25)
at Util.InstantDeSerializer.deserialize(InstantDeSerializer.java:21)
at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:69)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
at com.google.gson.Gson.fromJson(Gson.java:932)
at com.google.gson.Gson.fromJson(Gson.java:897)
at com.google.gson.Gson.fromJson(Gson.java:846)
at com.google.gson.Gson.fromJson(Gson.java:817)
at Source.JSONTryMe.main(JSONTryMe.java:85)
Here are several conceptual flaws:
Birth dates should use LocalDate
Your JSON input provides ISO datetime, but your deserializer tries to read milliseconds since epoch. Use LocalDate#parse() for this
Reading Events from CSV file into ESPER with POJO, the code below seams to scan through the file (larger files take longer), however no output is generated by events reaching listener.
the CSV file content is:
Geotimestamp,closeoutBid,closeoutAsk,tradable
"20170301 000000643",1.236550,1.236680,0
"20170301 000001893",1.236540,1.236680,0
"20170301 000002893",1.236550,1.236680,0
"20170301 000004410",1.236560,1.236700,0
"20170301 000006160",1.236540,1.236680,0
"20170301 000006393",1.236540,1.236670,0
The code is based on article here
import com.espertech.esper.client.*;
import com.espertech.esperio.csv.AdapterInputSource;
import com.espertech.esperio.csv.CSVInputAdapter;
import com.espertech.esperio.csv.CSVInputAdapterSpec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import java.io.File;
import java.time.Instant;
public class hAppY implements Runnable {
private static final Log log = LogFactory.getLog(AppMod.class);
public static void main(String[] args) {
SimpleLayout layout = new SimpleLayout();
ConsoleAppender appender = new ConsoleAppender(new SimpleLayout());
Logger.getRootLogger().addAppender(appender);
Logger.getRootLogger().setLevel((Level) Level.WARN);
new AppMod().run();
}
public hAppY() {
}
public void run() {
//The Configuration is meant only as an initialization-time object.
Configuration configuration = new Configuration();
// We register Ticks as objects the engine will have to handle
configuration.addEventType("HistData", HistDataEventClass.class);//.getName()
EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(configuration);
File file = new File("./data/DAT_ASCII_GBPUSD_T_201703.csv");
AdapterInputSource ais = new AdapterInputSource(file);
CSVInputAdapterSpec spec = new CSVInputAdapterSpec(ais, "HistDataEventClass");
spec.setUsingExternalTimer(true); //will not pause for time between ticks when true
EPAdministrator epAdmin = epService.getEPAdministrator();
String vel1 = "select count(*) from HistData()";//()from HistData().win:time(3 sec)";
EPStatement cepStatement1 = epAdmin.createEPL(vel1);
//attach 1st statement listener to cep statement obj
cepStatement1.addListener(new CEPListener());
(new CSVInputAdapter(epService, ais,"HistDataEventClass")).start();
}
public class HistDataEventClass {
private java.lang.String /*Instant*/ Geotimestamp;
private java.lang.String receivedTS;
private double closeoutBid;
private double closeoutAsk;
private byte tradable; //ignore
//c'tor
public HistDataEventClass(java.lang.String timestamp, java.lang.Double closeoutBid, java.lang.Double closeoutAsk, byte tradable) {
try {
this.receivedTS = Instant.now().toString(); //received time stamp at time of instantiation of event object (this)
this.Geotimestamp = timestamp;
// NEED TO PROPERLY PARSE THE TS
this.closeoutBid = Double.parseDouble(java.lang.String.valueOf(closeoutBid));
this.closeoutAsk = Double.parseDouble(java.lang.String.valueOf(closeoutAsk));
this.tradable = tradable;
}
catch (Exception e) {
e.printStackTrace();
}
}
// getters/setters
//timestamp
public java.lang.String getTimestamp() {
return this.Geotimestamp;
}
public void setGeoTimestamp(String ts) {this.Geotimestamp = ts;}
// receivedTS
public java.lang.String getReceivedTS() {return this.receivedTS;}
public void setReceivedTS(String rts) {this.receivedTS = rts;}
//CloseoutBid()
public double getCloseoutBid() {return this.closeoutBid;}
public void setCloseoutBid(double bid){this.closeoutBid=bid;}
//CloseoutAsk()
public double getCloseoutAsk() {return this.closeoutAsk;}
public void setCloseoutAsk(double ask){this.closeoutAsk=ask;}
//tradable()
public byte getTradable() {return this.tradable;}
public void setTradable(byte t){this.tradable=t;}
}
public class CEPListener implements UpdateListener { //removed static to satisfy compiler
public void update(EventBean[] newData, EventBean[] oldData) {
System.out.println("my print statement: " + newData[0].getUnderlying());
}
}//CEPListener
}
I have a Document case class.
To Serialize it and deserialize to and from Json text, I defined implicit Reads and Writes object.
If my Document class contains only Int and String, I have no problem.
However when I have an Html type value in my Document case class, I have the issue.
It is a nesting serialization and deserialization.
I have a problem creating a Reader for Html. Play 2 Html is not a case class. Is that a problem?
Is the following code is right:
implicit object HtmlReads extends play.api.libs.json.Reads[Html] {
def reads(json: JsValue) = Html (
(json \ "text").as[String]
)
}
It does not work.
How should I do it?
Thanks
This is how I solved this problem in java (but I guess it is the same in scala):
I create a JsonSerializer class to translate a class into a string and then I annote the fields which will be translate into Json with my class.
An exemple to show you how it work for the date:
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.stereotype.Component;
/**
* Used to serialize Java.util.Date, which is not a common JSON
* type, so we have to create a custom serialize method;.
*
* #author Loiane Groner
*/
#Component
public class JsonDateSerializer extends JsonSerializer<Date>{
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
#Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String formattedDate = dateFormat.format(date);
gen.writeString(formattedDate);
}
}
Then I annote the corresponding field with my class:
public class MyClass
{
#Formats.DateTime(pattern="dd/MM/yyyy")
#JsonSerialize(using=JsonDateSerializer.class)
public Date myDate;
}
Ainsi, lorsque j'utilise mapper.writeValueAsString(lst), j'obtiens des date au format: 08-13-2014
I copied the sources from Loiane Groner.
I have got xades XML as InputStream. I do not care if certyficates are valid, check sign, etc. I can't provide any CA or any other type of certificate storage/validation. What I need is just get documents embedded in xades file as streams or temporary files on disk so I can process them as they were plain files from disk. Could someone provide snippet that extracts embedded documents? TIA
To extract Base64-encoded signed content from XAdES signed file i use code like below. It doesn't use xades4j at all.
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.bouncycastle.util.encoders.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Utils {
/**
* extract ds:Object from .xades file
*
* #param xadesIn .xades file input stream
* #return base64 decoded bytes
* #throws Exception
*/
public static byte[] extractContentFromXadesSignedFile(InputStream xadesIn) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(xadesIn);
xadesIn.close();
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(new SimpleNamespaceContext(new HashMap<String, String>() {{
put("ds", "http://www.w3.org/2000/09/xmldsig#");
}}));
XPathExpression expr = xpath.compile("//ds:SignedInfo/ds:Reference");
NodeList referenceNodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
/**
* loop over all Reference nodes
* i need to find Object node with Id that fits URI value of Reference
*/
for(int i=0;i<referenceNodes.getLength();i++){
Node referenceNode = referenceNodes.item(i);
NamedNodeMap attributes = referenceNode.getAttributes();
if(attributes != null) {
Node uri = attributes.getNamedItem("URI");
if(uri != null) {
String objectId = uri.getNodeValue();
XPathExpression expr2 = xpath.compile("//ds:Object[#Id='"+objectId.substring(1)+"']");
Node contentNode = (Node) expr2.evaluate(doc, XPathConstants.NODE);
if(contentNode != null) {
String base64 = contentNode.getFirstChild().getNodeValue();
return Base64.decode(base64);
}
}
}
}
return null;
}
/**
* http://stackoverflow.com/a/6392700/404395
*/
private static class SimpleNamespaceContext implements NamespaceContext {
private final Map<String, String> PREF_MAP = new HashMap<String, String>();
public SimpleNamespaceContext(final Map<String, String> prefMap) {
PREF_MAP.putAll(prefMap);
}
#Override
public String getNamespaceURI(String prefix) {
return PREF_MAP.get(prefix);
}
#Override
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
#Override
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
}
}
Sample usage of that:
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;
public class XadesExtractTest {
#Test
public void extract() throws Exception {
InputStream in = XadesExtractTest.class.getClassLoader().getResourceAsStream("test.xades");
byte[] bytes = Utils.extractContentFromXadesSignedFile(in);
Assert.assertNotNull(bytes);
in.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
File f = File.createTempFile("test", ".zip");
System.out.println(f.getAbsolutePath());
FileOutputStream fout = new FileOutputStream(f);
IOUtils.copy(bin, fout);
bin.close();
fout.close();
}
}
If I get the following json from a RESTful client, how do I elegantly unmarshal the java.util.Date? (Is it possible without providing (aka. hard-coding) the format, that's what I mean by elegantly...)
{
"class": "url",
"link": "http://www.empa.ch",
"rating": 5,
"lastcrawl" : "2009-06-04 16:53:26.706 CEST",
"checksum" : "837261836712xxxkfjhds",
}
The cleanest way is probably to register a custom DataBinder for possible date formats.
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CustomDateBinder extends PropertyEditorSupport {
private final List<String> formats;
public CustomDateBinder(List formats) {
List<String> formatList = new ArrayList<String>(formats.size());
for (Object format : formats) {
formatList.add(format.toString()); // Force String values (eg. for GStrings)
}
this.formats = Collections.unmodifiableList(formatList);
}
#Override
public void setAsText(String s) throws IllegalArgumentException {
if (s != null)
for (String format : formats) {
// Need to create the SimpleDateFormat every time, since it's not thead-safe
SimpleDateFormat df = new SimpleDateFormat(format);
try {
setValue(df.parse(s));
return;
} catch (ParseException e) {
// Ignore
}
}
}
}
You'd also need to implement a PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import grails.util.GrailsConfig;
import java.util.Date;
import java.util.List;
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry reg) {
reg.registerCustomEditor(Date.class, new CustomDateBinder(GrailsConfig.get("grails.date.formats", List.class)));
}
}
and create a Spring-bean definition in your grails-app/conf/spring/resources.groovy:
beans = {
"customEditorRegistrar"(CustomEditorRegistrar)
}
and finally define the date formats in your grails-app/conf/Config.groovy:
grails.date.formats = ["yyyy-MM-dd HH:mm:ss.SSS ZZZZ", "dd.MM.yyyy HH:mm:ss"]
Be aware that the new version of Grails 2.3+ supports this type of feature out of the box.
See Date Formats for Data Binding
With that said, if you are forced to use a version of Grails prior to 2.3, the CustomEditorRegistrar
can be updated using the following code to eliminate the deprecation warning, and also uses the #Component annotation, which allows you to remove / skip the step of adding the bean directly in resources.groovy.
Also not that I changed the grails configuration property name to grails.databinding.dateFormats, which matches the property now supported in Grails 2.3+. Finally, my version is a .groovy, not .java file.
import javax.annotation.Resource
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
import org.springframework.stereotype.Component
#Component
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
#Resource
GrailsApplication grailsApplication
public void registerCustomEditors(PropertyEditorRegistry reg){
def dateFormats = grailsApplication.config.grails.databinding.dateFormats as List
reg.registerCustomEditor(Date.class, new CustomDateBinder(dateFormats))
}
}