JSON string to byte[] JSONParseException - json

I've gotten a whole bunch of angularJS, rest and entity stuff working together to be able to save form data via REST in my POSTGRES DB.
However, I decided to try something different with one of the entity fields so that I can store longer bits of text in the DB. I wanted to use an Entity with a field as follows:
#Column
private int age;
#Lob
#Column(length = 2147483647)
private byte[] otherNeeds;
Now the entity was created just fine. I built my REST interface on top of that based from JBoss Forge scaffolding. Everything works fine with my saving of the form via REST as long as I keep the "otherNeeds" field empty.
Here's my form:
<input id="age" type="number" ng-model="primaryGuest.age"></input>
<input id="otherNeeds" type="text" ng-maxlength="2147483647" ng-model="primaryGuest.otherNeeds"></input>
All this data is passed through correctly into my JavaScript objects in AngularJS, and when I click the save() button, I can see the POST request go thru to my REST interface with the following payload:
{
otherNeeds: "jjjjjj"
age: "10"
}
However, the response back from the server is an exception:
Caused by: org.codehaus.jackson.JsonParseException: Failed to decode VALUE_STRING as base64 (MIME-NO-LINEFEEDS): Illegal character '"' (code 0x22) in base64 content
at [Source: org.apache.catalina.connector.CoyoteInputStream#1a37992c; line: 1, column: 67]
at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1433) [jackson-core-asl-1.9.9-redhat-2.jar:1.9.9-redhat-2]
at org.codehaus.jackson.impl.Utf8StreamParser.getBinaryValue(Utf8StreamParser.java:402) [jackson-core-asl-1.9.9-redhat-2.jar:1.9.9-redhat-2]
at org.codehaus.jackson.map.deser.std.PrimitiveArrayDeserializers$ByteDeser.deserialize(PrimitiveArrayDeserializers.java:289)
at org.codehaus.jackson.map.deser.std.PrimitiveArrayDeserializers$ByteDeser.deserialize(PrimitiveArrayDeserializers.java:275)
at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:299)
at org.codehaus.jackson.map.deser.SettableBeanProperty$MethodProperty.deserializeAndSet(SettableBeanProperty.java:414)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:697)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2704)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315)
at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:419)
at org.jboss.resteasy.core.interception.MessageBodyReaderContextImpl.proceed(MessageBodyReaderContextImpl.java:105) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.read(GZIPDecodingInterceptor.java:63) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.interception.MessageBodyReaderContextImpl.proceed(MessageBodyReaderContextImpl.java:108) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:169) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
... 33 more
So, I'm not sure how to handle this scenario to have my object be transformed into something that would be acceptable for the byte[] format. I have the option of going back to a standard "String" field but I want to be able to provide the user with an "unlimited" amount of text that they can provide.
Any suggestions would be much appreciated.

I'm not exactly sure what the issue was with the #Lob type column and why it didn't want to push the data into the DB; however, eventually, I changed from
#Lob
to
#Type(type="org.hibernate.type.StringClobType")
private String otherNeeds;
And then I was able to manage this more straightforwardly and push content into the DB via the REST calls.

When the property type is byte[] and the response is in String jackson thinks the data is base64 encoded and tries to decode it and convert it to byte[]. But when you changed the type to String no such conversion is taking place and the string is directly saved in database.

Related

Create list of custom objects from flat JSON data

I want to create an arraylist of type Adapter from a JSON. But since the JSON is not in arraylist format, I'm unable to use gson.fromJson() method.
Is there any way by which I can create a list of my custom object by parsing the following JSON?
JSON data:
"source":{"adapter-config.adapter[0].name":"testAdapter1",
"adapter-config.adapter[0].resolverName":"serviceResolver",
"adapter-config.adapter[0].parameters[0].key":"serviceId",
"adapter-config.adapter[0].parameters[0].value":"serviceIdPathInEvent",
"adapter-config.adapter[0].parameters[1].key":"appId",
"adapter-config.adapter[0].parameters[1].value":"appIdPathEvent",
"adapter-config.adapter[0].parameters[2].key":"env",
"adapter-config.adapter[0].parameters[2].value":"envPathInEvnet"}
My Adapter Object:
public class Adapter {
private String name;
private String resolverName;
private List<KeyValuePair<String, String>> attributeList;
}
Gson does not provide such functionality out of the box. However you can achieve this by manually reading the JSON data from a JsonReader, consuming the JSON property names with nextName() and then parsing them to determine which data they represent. You could either directly read from a JsonReader, or in case the shown JSON data is only an extract from a larger JSON document, you can implement a TypeAdapter for your List<Adapter>. That TypeAdapter could then either be registered with a GsonBuilder by providing new TypeToken<List<Adapter>>() {}.getType() as type, or you could annotate the field holding the List<Adapter> with #JsonAdapter.
For the actual parsing of List<Adapter>, I would recommend storing a current adapter (and its index in the list) in a local variable. Whenever you parse a JSON property name, you could then check if the index encoded in the name is equal to the index of the current adapter, then you are going to modify the existing instance, otherwise if the encoded index is equal to the index of the current adapter + 1 you create a new Adapter instance, add it to the list of adapters and reassign the current adapter variable and its index variable. Then you continue with parsing the remainder of the property name to find out which Adapter field values to set.
(In case you get stuck there, feel free to let me know in the comments and I can try to provide some concrete code; but it would probably be best if you tried it yourself first.)

How to display Blob /Json data field in Liferay 7.2?

I am using a service builder that is retrieving the form data fine from mysql db. I have a field that has the json data and I tried to map it using object mapper and using com.fasterxml.jackson.databind.ObjectMapper to display the json content. However, the Blob Data is shown as: com.mysql.cj.jdbc.Blob#4ca74f7f
How do I actually get/extract the data from the storing link above? Here is my code snippet:
for (ddmcontent MyTemp : myList) {
System.out.println("Content ID : "+myList.getContentId());
System.out.println("User Blob Data : "+myList.getData());
Blob responseBody =myList.getData();
ObjectMapper objectMapper = new ObjectMapper();
List<ModelData> myDat = objectMapper.readValue((DataInput)
responseBody,objectMapper.getTypeFactory().constructCollectionType
(List.class,ModelData.class));
for (ModelData dt : myDat) {
System.out.println("User Name : "+dt.Name);
System.out.println("Users Email : "+dt.Email);
}
}
Please note, I have defined my ModelData elements as all String.
Any suggestion? What am I missing?
Thanks in advance!
The toString() representation hints at the object's type com.mysql.cj.jdbc.Blob. If you look up its javadoc (or the interface it implements) you'll see the options that you have to decode the contents of the Blob, namely getting an InputStream or a byte[] representation, which you'd have to subject to the correct character set decoding to turn it into a String.
Make sure you nail the character set by testing it with all kinds of Unicode content, so that you don't have to fix badly encoded database content later when your table contains a lot of data in unknown encodings.
As you're using Liferay's Service Builder, you might want to share the relevant parts of your service.xml (optional model-hints.xml) to check for an easier implementation.
I finally got this working by changing the field in question to String and addining a max length to certain number of Char
Thanks!

Error while getting JSON when data has spaces

I am facing issue while fetching json data when data has white spaces .
I am using spring,
In spring controller i am doing like below,
String json=new Gson().toJson(agents, new TypeToken>() {
}.getType())
I am able to see proper json in logger too, after that I am setting to model attribute like below one
model.addAttribute("json",json);
here model is 'org.springframework.ui.ModelMap'
In JSP I am able fetching data till no space found.
Example :
Original JSON String: ILOVE JAVA
Fetching string in JSP: ILOVE
Only please help me out this with out using encoding string.

Java validator for String

How do I validate using Hibernate validator for elements appearing more than once in a JSON payload bound to a Java class annotated with validator annotations?
Let's say I have the following:
class Person {
String name;
int age;
}
I am binding JSON to Person.
The JSON payload looks like the following:
{
"name":"someName",
"age":30
}
Let's say the payload has 2 "name" fields repeated as below.
{
"name":"someName",
"name" : "otherName",
"age":30
}
Then I like to use the validator to validate this. It will work for Collection objects if I use #Size(min=1, max=1).
I am wondering how I make this work for String. With String #Size tries to look for the length of the string content and not the number of times the string content in the payload.
Thanks for your time!
This is not possible. JSON deserialization and Bean validation are two entirely different things. By the time your Hibernate validation kicks in all it sees is a Person object, with a single name field.
It is the behavior of your JSON library that will determine which of the "name" fields will be deserialized into the Java bean (or if an exception will be thrown). For the most part, if you want to validate that no duplicates are supplied then you are going to need to write some custom deserialization code.

Accept only number formats for a property from JSON

I am developing ASP.Net Web API application and we are exposing a REST API for different clients. I have a problem when taking users' JSON files and converting them to Data Model classes. My JSON looks like below.
{"engagementid":1,"clientname":"fsdfs","myno":"23,45","address1":"fsd","address2":"fsdfs","city":"fsdfs","zip":"fsdf","info":"fsdfs","country":"fsdfs","currency":"NOK"}
You can see that my "myno" is sent as a string. But in my Server Data Model "myno" is a double value. So what happen here is when I send the value for "myno" as "23,45", it gets assigned to MyNo property of my Model as 2345. This is wrong, because you can see that the number has been changed because of this wrong conversion. What I simply need is to restrict this conversion. I mean, I want to send an error to Client if he sends a string for "myno" property. Since it is a double value in my Server Data Model, I want to accept only numbers from the client for this property. Which means, I want it like this.
{"myno":2345} //correct
{"myno":"2345"} //wrong. I want to send a error to user by saying, "We only accept Numbers for this value"
How do I do this?
Update:
This problem gets solved if I am using int in my server-model. I mean, if a client send a string to a property which is represented as int in my model, then it gives an error to user by saying string to int conversion can not be done.
I don't whether it is correct or not. I am just telling my suggestion according to my experience. Why can't you create a custom validation attribute and check the datatype of data.
public class IsNumberAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if(value.GetType() != Int)
return new ValidationResult("Only Numbers Allowed");
return null;
}
}