JSON - Convert Object to JSON Array - java

i try to convert a class object which are generated via Reflection and convert them to JSON string. following is my methods
public Object creatObjectAsString(String className) {
Object objects = null;
try {
objects = java.lang.reflect.Array.newInstance( Class.forName(className), 1);
//System.out.println(objects.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return objects ;
}
public String convertPlainObjectToJSON( Object obj,boolean isArray){
String jsonString="",tempJSON="";
JSONSerializer serializer = new JSONSerializer();
tempJSON = serializer.serialize(obj);
if(isArray){
jsonString="["+tempJSON+"]";
}else{
jsonString=tempJSON;
}
return jsonString;
}
I have hard coded the following lines since i did not know how to create JSON Array which is not the correct way of programming.
if(isArray){
jsonString="["+tempJSON+"]";
}else{
jsonString=tempJSON;
}
when i printed the convertPlainObjectToJSON result of method i get the following [[null]] which is not expected.
what is the mistake i make.
Please correct me.

If you notice your output, you can see [[ (double square braces), which means the JSONSerializer has already converted it to an JSONArray. Therefore, you needn't do it again manually.
And regarding the null between them, it is because you're passing null to the convertPlainObjectToJSON. Send a newly created object array (as #MvG mentioned), new Object[0], and you'll get what you want!
Always remember that blank and null are not the same!

Related

Saxon-HE Java Extension - How to I access the value of a xsl-variable which is passed as a parameter?

I have created a function using the Saxon documentation which has 3 parameters. The function takes an input string and pads it out to a specific size using an integer and string values.
padStringLeft(inputStr,size,padChar)
If I put this in my XSLT and hard wire the parameters the function works.
<debug1><xsl:value-of select="c4j_XSLT_Ext_padStringLeft:padStringLeft('1',4,'0')" /></debug1>
The output from the above would be '0001'
When I pass the contents of a XSLT variable however and set a debug / break point in my java function I can see that I'm getting param0 as a lazysequence.
<debug2><xsl:value-of select="c4j_XSLT_Ext_padStringLeft:padStringLeft($myvar,4,'0')" /></debug2>
Java function
As my code is attempting to treat it as a string it does not work.
How should I be handling this scenario, how do I access the value or the xsl-variable/param and what if sometimes I want to use a literal string instead of a variable?
public class XSLT_Ext_padStringLeft extends ExtensionFunctionDefinition
{
#Override
public SequenceType[] getArgumentTypes()
{
return new SequenceType[]{SequenceType.SINGLE_STRING,SequenceType.SINGLE_INTEGER, SequenceType.SINGLE_STRING};
}
#Override
public StructuredQName getFunctionQName()
{
return new StructuredQName("c4j_XSLT_Ext_padStringLeft", "http://com.commander4j.Transformation.XSLT_Ext_padStringLeft", "padStringLeft");
}
#Override
public SequenceType getResultType(SequenceType[] arg0)
{
return SequenceType.SINGLE_STRING;
}
#Override
public ExtensionFunctionCall makeCallExpression()
{
return new ExtensionFunctionCall() {
#Override
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
String inputStr;
try
{
inputStr = ((StringValue)arguments[0]).getStringValue();
} catch (ClassCastException ex)
{
inputStr = "";
}
long size;
try
{
String temp =arguments[1].toString();
size = Integer.valueOf(temp);
} catch (ClassCastException ex)
{
size = 1;
}
String padStr;
try
{
padStr = ((StringValue)arguments[2]).getStringValue();
} catch (ClassCastException ex)
{
padStr = "";
}
String result = inputStr;
while (result.length() < size)
{
result = padStr + result;
}
return StringValue.makeStringValue(result);
}
};
}
}
Thanks
Dave
In general the parameters are passed as instance of the class net.sf.saxon.om.Sequence, and you should only use the methods on the interface Sequence, rather than examining what particular kind of Sequence it is, because that could change in the future.
If you're expecting a singleton sequence (that is, a single item), call head() to get the first item in the sequence (this will return null if the sequence is empty). You will then have an instance of net.sf.saxon.om.Item. (The Sequence might already be an Item, because an item is a sequence, but you can't rely on that, and calling head() is safer than casting.) If you're expecting a string, you can safely call getStringValue() on this item to get the value as a string.
Also note, Saxon uses lazy evaluation wherever possible, which means that the string might not actually be computed until someone asks for its value. This means that innocent-looking calls like head() and getStringValue() can actually throw exceptions, and you need to be prepared for this.
So in short, you should replace
inputStr = ((StringValue)arguments[0]).getStringValue();
with
inputStr = arguments[0].head().getStringValue();
Also note, Saxon uses lazy evaluation wherever possible, which means that the string might not actually be computed until someone asks for its value. This means that innocent-looking calls like head() and getStringValue() can actually throw exceptions, and you need to be prepared for this.
So if I understand you correctly - when I call Transform to process the XSLT transformation it will call each of my custom java external functions as needed but the reference to
inputStr = arguments[0].head().getStringValue();
could generate an exception?
I would then need to do something within the java function to force it to get the value - or would I let the exception propogate back to the calling Transformation and catch it there ?
Dave

Why ToStringBuilder(ToStringStyle.JSON_STYLE) adding quotes before and after object? is it True

i want to send json request with my java classes but When i try to send my jsonObject, I think the outgoing object went wrong.
This is true object:
{
"brandCode":659599,
"isNotAutoSendIYS": "false",
"consentData": {
"consentDate":"2020-07-20 00:00:00",
"source":"HS_MESAJ",
"status":"ONAY",
"retailerCode":null,
"retailerAccess":[],
"recipient":"ornek#mysoft.com.tr",
"recipientType":"BIREYSEL",
"type":"EPOSTA"
}
}
This is my jsonObject from class:
{
"brandCode":659599,
"isNotAutoSendIYS":false,
"consentData":"{\"consentDate\":\"2020-07-20 00:00:00\"
,\"source\":\"HS_MESAJ\",
\"status\":\"ONAY\",
\"retailerCode\":null,
\"retailerAccess\":[\"\"],
\"recipient\":\"ornek#mysoft.com.tr\",
\"recipientType\":\"BIREYSEL\",
\"type\":\"EPOSTA\"}"
}
If you have noticed, double quotes are opened after the consentData object and double quotes at the end of the object are closed. How can i fix this situation or this situation is true ? I'am using ToStringBuilder class.
This ConsentDataReqType.class :
public String toStringValidate(){
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).append("brandCode", brandCode).append("isNotAutoSendIYS", isNotAutoSendIYS).append("consentData", consentData.toStringValidate()).toString();
}
This ConsentData.class:
public String toStringValidate(){
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).append("consentDate", consentDate).append("source", source).append("status", status)
.append("retailerCode",retailerCode).append("retailerAccess",retailerAccess).append("recipient",recipient).append("recipientType",recipientType)
.append("type",type).toString();
}
When you do:
.append("consentData", consentData.toStringValidate())
As far as append is concerned, the value being appended is a string, and so must be escaped. There is no way to know that it is actually a JSON value and can be inserted 'raw'.
If you want JSON, I would use a real JSON library, e.g. Gson.
If you just need a string which is unique for objects which have different values for their members you could do:
public String toStringValidate() {
return new ReflectionToStringBuilder(this, new RecursiveToStringStyle() {
{
setUseIdentityHashCode(false);
}
}).build();
}

Get the data type of JSON element in Java

I get a JSON value from Kafka queue and I want to get the right data type to save it in the DB.
Value can be: String, int, double or array.
How can i detect automatically the right datatype and create a Java Object from it?
My first steps:
check if json is an array or not:
if (jsonValue.isJsonPrimitive()) {
// create new Object
//ToDo need to parse int, double not only to string
new ValueObject(time,jsonValue.getAsString);
} else if (jsonValue.isJsonArray()) {
//create new Object
//ToDo need to parse int, double string
new ValueObject(time,jsonValue.getAsJsonArray());
}
How can I design the ValueObject class to convert the value to the corresponding data type and return the right object?
Thanks for any ideas
have you tried:
//this instanciates an object of the getClass() method output
Object output = jsonValue.getClass().cast(jsonValue);
if that didn't work, you can try instanceof:
if(jsonValue instanceof int){
int output = (int) jsonValue;
}...
I hope that will do.
if you are using jackson lib, you can do like this:
JsonNode rootNode = objectMapper.readTree(json);
Iterator<String> fields = rootNode.fieldNames();
while(fields.hasNext()){
String field = fields.next();
JsonNode obj = rootNode.get(field);
System.out.println("value " + obj);
if (obj.isInt()) {
System.out.println("Integer");
}
if (obj.isDouble()) {
System.out.println("Double");
}
if (obj.isTextual()) {
System.out.println("String");
}
}

Java Reflection - get method without specific parameters type

I am trying to get the method by java reflection, but i don't want to be specific about the parameters classes in getMethod().
public Object prepareFilter(String filter, String sort) {
Class filterClass = this.filterClass;
try {
Method createCriteriaMethod = filterClass.getMethod(CREATE_CRITERIA_METHOD);
Method orderByClauseMethod = filterClass.getMethod(ORDER_BY_CLAUSE_METHOD, String.class);
Class criteriaClass = createCriteriaMethod.getReturnType();
Object filterObject = filterClass.newInstance();
Object criteriaObject = createCriteriaMethod.invoke(filterObject);
for (ExtFilterRequest extFilter : ExtFilterRequest.decodeJson(filter)) {
StringBuilder sb = new StringBuilder()
.append(AND)
.append(WordUtils.capitalize(extFilter.getProperty()))
.append(extFilter.getCondition());
Method criteriaConditionMethod = criteriaClass.getMethod(sb.toString(), ????); // earlier extFilter.getTransformedValue().getClass()
criteriaConditionMethod.invoke(criteriaObject, extFilter.getTransformedValue());
}
String orderByClause = ExtSortRequest.getOrderByString(sort);
if (orderByClause != null)
orderByClauseMethod.invoke(filterObject, orderByClause);
return filterObject;
} catch (Exception e) {
// later
}
return null;
}
I have the methods generated by MyBatis and I want to call them by reflection with the decoded json that comes from extjs client. It looks like: operator, value and property. Following code is working with string values but i dont know what to put in the place of question marks when I call for example method which get a Date value (decoded value is always a string).
Is it possible to call getMethod with some hmm.. generic type and get the specific method? Or should I do it in another way?
Summarizing - if I have method like this:
public Criteria andSomeReferenceIsEqualTo(String value) {
addCriterion("some_ref =", value, "someRef");
return (Criteria) this;
}
and this
public Criteria andPrimDateEqualTo(Date value) {
addCriterionForJDBCDate("prim_date =", value, "primDate");
return (Criteria) this;
}
I want to call them in the same way by method I specify earlier - even if its boolean, list of values, string or integer.

jackson: catch exceptions for single items when deserializing a list

I have the following problem: There's a REST API that returns a JSON String that I want to map to List. MyObject has several fields, some of them int/double. Let's consider the API could be returning Strings instead of ints/doubles for one of those fields for SOME of the MyObjects, the rest is okay.
Now I want the mapper to still map this to a List while throwing out the faulty MyObjects. However, calling
objectMapper.readValue(jsonString, TypeFactory.defaultInstance().constructCollectionType(List.class, MyObject.class));
will either succeed if all MyObjects are okay or fail completely when facing the first problem.
I was hoping to, kind of, find a spot where the mapper iterates over a list of JSON-MyObjects and mapping them to Java-MyObjects one by one. That way I'd be able to override that behavior and maybe surround it with a try-catch block and catch any exception that occurs while mapping a single MyObject. No luck so far, but maybe I'm just blind.
Any idea how to accomplish this with jackson is much appreciated.
I was able to achieve this by using Jackson's custom deserializer:
Here is my MyObject target class. It has an annotation which associate with it a custom deserializer:
#JsonDeserialize(using = MyObjectDeserializer.class)
public class MyObject
{
public int num;
public String str;
#Override
public String toString()
{
return "{" + num + "," + str + "}";
}
}
Here is the custom deserializer. it checks if the type of the "num" property is int typed:
public class MyObjectDeserializer extends JsonDeserializer<MyObject>
{
// read current MyObject json node
JsonNode myObjectNode = jp.getCodec().readTree(jp);// this will read
// read "num" property into JsonNode and check what subclass was created
JsonNode numNode = myObjectNode.get("num");
if (numNode instanceof IntNode) { // test if value of num is int indeed
MyObject o = new MyObject();
o.num = ((IntNode)numNode).intValue(); // read int value
o.str = ((TextNode)myObjectNode.get("str")).asText(); // this is how to read string typed property
return o;
} else {
return null; // or any default/error value
}
}
now assuming the following input, notice the 2nd object has a string typed "num" property:
[{"num":1,"str":"n1"}, {"num":"s","str":"n2"}, {"num":3,"str":"n3"}]
without the custom deserializer, you would get an exception. and with it you get the output:
[{1,n1}, null, {3,n3}]

Categories