How can I parse invalid JSON to Java Object using Pojo Class - java

I'm not sure what format this object is in but can I parse the following invalid JSON object to Java class Pojo? I tried doing it using Jackson but since it's invalid, I was wondering if pojo class would work?
{
name: (sindey, crosby)
game: "Hockey"
type: athlete
}
The file would have multiple objects of this format

Geesh, don't recognise this format! If you want to use Jackson you could pre-process you data to wrap the values... perhaps a regex to catpure the groups and wrap the values in quotes something like (name|type):\s(.+) => $1: "$2"
I was wondering if pojo class would work?
Sure, you could make that work with a simple parser; plenty of room for improvement, but something like this would do it:
Record record = null;
var records = new LinkedList<>();
// I'm using a reader as example, but just provide lines any way you like
while ((line = reader.readLine()) != null) {
line = line.trim();
// may need to skip empty lines if you have them in your file...
if (line.equals("{")) {
record = new Record();
records.add(record);
} else {
// may need substrings if your data contains ":"
var tokens = line.split(":");
var field = tokens[0];
var value = tokens[1];
if (field.equals("name")) {
// perhaps shuffle the format to something nicer here..
record.setName(value);
}
/// same for game and type fields...
}
}

Related

Reading a csv file into an array in Java (the add method not working)

I am trying to implement a csv reader into my class in Java using eclipse. I keep getting an error for the add method "add(Person) in the type list is not applicable for the arguments (String[]). What am I doing wrong?
public static List<Person> readPersons(String fileName)
throws FileNotFoundException {
int count = 0;
List<Person[]> content = new ArrayList<>();
try(BufferedReader cv = new BufferedReader(new FileReader(fileName))){
String line = "";
while ((line = cv.readLine()) != null) {
content.add(line.split(","));
}
} catch (FileNotFoundException e) {
}
return content;
}
Also, how do I implement this FileNotFoundException extender? It is required in the program.
The line.split( "," ) method will return an array of strings.
What it does is: The original string line is split into an array of strings. In that array, every string is a substring of line which is separated by a comma.
For example, if line is "Peter,Smith,38", the following array of strings will be returned: [ "Peter", "Smith", "38" ].
But, since your List only can contain objects of the type Person, it cannot take the String[] array returned by line.split( "," ).
So assuming you have an Constructor for Person that looks like this: Person( String firstName, String secondName, int age ) you would have to change your while loop to something like this:
while ( ( line = cv.readLine( ) ) != null )
{
// Get the data from the CSV object
String[] csvData = line.split( "," );
// Create a Person object with the retrieved data
Person personFromCsvLine = new Person( csvData[0], csvData[1], Integer.parseInt( csvData[2] );
// Now you can add the person object to your list
content.add( personFromCsvLine );
}
The answer by be-ta is correct.
I would like to point out that for reading a CSV you might want to consider using an existing solution in your code, like:
Apache Commons CSV
Jackson CsvMapper
Example code
These libraries will help with quoted / unquoted columns and conversion of values to the proper datatypes.

How to convert from Json to Protobuf?

I'm new to using protobuf, and was wondering if there is a simple way to convert a json stream/string to a protobuf stream/string in Java?
For example,
protoString = convertToProto(jsonString)
I have a json string that I want to parse into a protobuf message. So, I want to first convert the json string to protobuf, and then call Message.parseFrom() on it.
With proto3 you can do this using JsonFormat. It parses directly from the JSON representation, so there is no need for separately calling MyMessage.parseFrom(...). Something like this should work:
JsonFormat.parser().merge(json_string, builder);
//You can use this for converting your input json to a Struct / any other Protobuf Class
import com.google.protobuf.Struct.Builder;
import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat;
import org.json.JSONObject;
JSONObject parameters = new JSONObject();
Builder structBuilder = Struct.newBuilder();
JsonFormat.parser().merge(parameters.toString(), structBuilder);
// Now use the structBuilder to pass below (I used it for Dialog Flow V2 Context Management)
Since someone asked about getting the exception "com.google.protobuf.InvalidProtocolBufferException: JsonObject" when following Adam's advice--I ran into the same issue. Turns out it was due to the google protobuf timestamps. They are being serialized as an object containing two fields "seconds" and "nanos", since this isn't production code, I just got around this by parsing the JSON using jackson, going through the JSON object recursively and changing every timestamp from an object to a string formatted as per RFC 3339, I then serialized it back out and used the protobuf JSON parser as Adam has shown. This fixed the issue. This is some throwaway code I wrote (in my case all timestamp fields contain the word "timestamp", this could be more robust, but I don't care):
public Map<String, Object> fixJsonTimestamps(Map<String, Object> inMap) {
Map<String, Object> outMap = new HashMap<>();
for(String key : inMap.keySet()) {
Object val = inMap.get(key);
if(val instanceof Map) {
Map<String, Object> valMap = (Map<String, Object>)val;
if(key.toLowerCase().contains("timestamp") &&
valMap.containsKey("seconds") && valMap.containsKey("nanos")) {
if(valMap.get("seconds") != null) {
ZonedDateTime d = ZonedDateTime.ofInstant(Instant.ofEpochSecond((int)valMap.get("seconds")).plusNanos((int)valMap.get("nanos")),
ZoneId.of("UTC"));
val = d.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
}
} else {
val = fixJsonTimestamps(valMap);
}
} else if(val instanceof List && ((List) val).size() > 0 &&
((List) val).get(0) instanceof Map) {
List<Map<String, Object>> outputList = new ArrayList<>();
for(Map item : (List<Map>)val) {
outputList.add(fixJsonTimestamps(item));
}
val = outputList;
}
outMap.put(key, val);
}
return outMap;
}
Not the most ideal solution but it works for what I am doing, I think I saw someone recommend using a different timestamp class.
You can convert json string to Proto using builder and json String
Example :
YourProto.Builder protoBuilder = YourProto.newBuilder();
JsonFormat.parser().merge(JsonString, protoBuilder);
If you want to ignore unknown json field then
YourProto.Builder protoBuilder = YourProto.newBuilder();
JsonFormat.parser()..ignoringUnknownFields().merge(JsonString, protoBuilder);
Another way is, to use mergeFrom method from ProtocolBuffer
Example :
YourProto.Builder protoBuilder = YourProto.newBuilder();
protoBuilder.mergeFrom(JsonString.getBytes());
Once it execute, you will get all the data in protoBuilder from json String
online service:
https://json-to-proto.github.io/
This tool instantly converts JSON into a Protobuf. Paste a JSON structure on the left and the equivalent Protobuf will be generated to the right, which you can paste into your program. The script has to make some assumptions, so double-check the output!

Parse a csv String and map to a java object

I am trying to parse a csv string like this
COL1,COL2,COL3
1,2,3
2,4,5
and map columns to a java object-
Class Person{
COL1,
COL2,
COL3;
}
Most of the libraries I found on google are for csv files but I am working with google app engine so can't write or read files. currently I am using split method but problems with this approach is
column that I am getting in csv string could vary as
COL1,COL3,COL2
don't want to use boiler plate code of splitting and getting each column.so what I need is list of column header and read all columns in a collection using header mapper. While iterating, map column value to a java object.
There are several question based on similar type of requirement but none of them helped me.
If anyone has done this before please could you share the idea? Thanks!
After searching and trying several libraries, I am able to solve it. I am sharing the code if anyone needs it later-
public class CSVParsing {
public void parseCSV() throws IOException {
List<Person> list = Lists.newArrayList();
String str = "COL1,COL2,COL3\n" +
"A,B,23\n" +
"S,H,20\n";
CsvSchema schema = CsvSchema.emptySchema().withHeader();
ObjectReader mapper = new CsvMapper().reader(Person.class).with(schema);
MappingIterator<Person> it = mapper.readValues(str);
while (it.hasNext()) {
list.add(it.next());
}
System.out.println("stored list is:" + (list != null ? list.toString() : null));
}}
Most of the libraries I found on google are for csv files but I am
working with google app engine so can't write or read files
You can read file (in project file system).
You can read and write file in blobstore, google cloud storage
Use a Tokenizer to split the string into objects then set them to the object.
//Split the string into tokens using a comma as the token seperator
StringTokenizer st = new StringTokenizer(lineFromFile, ",");
while (st.hasMoreTokens())
{
//Collect each item
st.nextElement();
}
//Set to object
Person p = new Person(item1, item2, item3);
If the columns can be reversed, you parse the header line, save it's values and and use it to decide which column each token falls under using, say, a Map
String columns[] = new String[3]; //Fill these with column names
Map<String,String> map = new HashMap<>();
int i=0;
while (st.hasMoreTokens())
{
//Collect each item
map.put(columns[i++], st.nextElement());
}
Then just, create the Person
Person p = new Person(map.get("COL1"), map.get("COL2"), map.get("COL3"));

Jackson Object mapping approach with Linkedin Rest API

When dealing with Linkedin Rest API, a lot of the fields has format like this:
"positions":
{
"_total": 1,
"values": [{"title": "Software Developer"}]
}
instead of:
"positions":
{
[{"title": "Software Developer"}]
}
This causes a lot of trouble when I try to map the json to a Position object. I am using Java with Jackson to parse the JSON response. Is there a way to set up object mapper so that it would automatically ignore the "_total" and "values" field?
I think it is not possible to configure ObjectMapper to do this automatically.
You could try writing your own parser, something along these lines:
JsonFactory f = new JsonFactory();
JsonParser jp = f.createJsonParser(new File("positions.json"));
List<Position> positions = new LinkedList<Position>();
jp.nextToken(); // will return JsonToken.START_OBJECT (verify?)
while (jp.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jp.getCurrentName();
jp.nextToken(); // move to value, or START_OBJECT/START_ARRAY
if ("positions".equals(fieldname)) { // contains an object
Position pos = new Position();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String namefield = jp.getCurrentName();
jp.nextToken(); // move to value
if ("value".equals(namefield)) {
pos.setValue(jp.getText());
}
}
}
jp.close();
Obviously #kpentchev provided a viable solution to this issue, but I personally tend to avoid manual parser as much as possible. In this case, I ended up writing a sort of wrapper class to map the raw json:
public class PositionWrapper
{
private Long _total;
private List<Position> values;
//setter and getter
}
Although it's a bit redundant this way, but it avoids going with a manual wrapper. Works well for me, even for nested objects.

How to return PHP array and receive it with Java

I have this on my webservice:
function listar($username)
{
$result = mysql_query("SELECT Name FROM APKs WHERE Tipo=0");
//$registo = mysql_fetch_array($result);
$numero = 0;
while($registo = mysql_fetch_array($result))
{
$regs[$numero] = $registo['Name'];
$numero++;
}
return $regs;
//return mysql_fetch_array($result);
}
in Java, after the SOAP call (not relevant now) I read it this way:
Object response = envelope.getResponse();
String x = response.toString();
I need to access which one of those fields (selected from the database) so I thought, why not split the array into strings?
I tried two methods:
String[] arr=x.split(" ");
System.out.println("Array :"+arr.length);
for(int i=0;i<arr.length;i++)
{
..
}
StringTokenizer stArr=new StringTokenizer(x," ");
while(stArr.hasMoreTokens())
{
...
}
But none of them worked, whick make me believe I'm returning badly the array in first place.
Any help?
UPDATE:
So I'm using again xsd:string;
Now I have on my webservice return json_encode($regs);
To convert the object from the response I'm using a specific google api
http://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
Object response = envelope.getResponse();
Gson gson = new Gson();
String jstring = gson.toJson(response);
But I'm with difficulty parsing the "jstring" because it's format: "[\"SOMETHING\",\"SOMETHING\",\"SOMETHING\",\"SOMETHING\",.....]". I have not any identifier to get those values.
How can I extract those dynamic values and assign them to String[]?
USE:
json_encode($array); in PHP
and
JSONObject in Java to read.
See this example: http://www.androidcompetencycenter.com/2009/10/json-parsing-in-android/
UPDATE
Change the line:
$regs[$numero] = $registo['Name'];
to:
$regs[] = array('name' => $registo["name"]);
If you need to get the ID, you also can do:
$regs[] = array('name' => $registo["name"], 'id' => $registo["id"]);
FORGET:
The mysql_fetch_array returns a real array not a string. It's not needed to split a string.
Be sure that your PHP Web Service is returning a xsd:array
Generate a new proxy using some generator like http://www.soapui.org. Just use the proxy. Nothing else.
Try to use JSON and you can esy build easy object and read it.

Categories

Resources