Why simplexml set NULL to field if in xml it is empty? - java

Considering this code:
public class Param {
#Text(required = false)
protected String param;
public String getValue() {
return param;
}
}
And I have this xml:
<item key="Key"></item>
After parsing this xml getValue() returns me null instead of empty string.
Why is this Behaviour?

This behavior refer that it found have an empty (not space) value. So the String bind to that not even initialize (will not occupies memory).
as String a=""; is a initialized variable and it have memory allocated on low level. Otherwise there is no need of initialization if it is set empty. It can be costly for enterprise applications for class objects.
MORE
About string is a char array and each char is assosiated with ASCII value
Test it
String a="";
System.out.println(a));
output:
//[B#459bdb65
and
String a;
System.out.println(a));
output:
java.lang.RuntimeException: Uncompilable source code - variable a might not have been initialized
Where about char
char a='A';
System.out.println((int)a);
output:
65

AFAIK the behaviour you're experiencing is the expected with your code.
If you want to make empty element be returned as empty string instead of null, the best way is to build a Converter.
Another way is via annotation and use the behaviour, you can annotate it as required:
#Element(name = "PARAM", required = true)
private String param;
The required = true will throw an exception if drop is empty. You can use this if an empty drop is not allowed.
A second way is set required = false so will be deserialized to null if it's empty:
boolean isEmpty = ( a.getParam() == null );

Related

OpenCSV - CsvReaderNullFieldIndicator seems to make no difference

I am using opencsv to create a CsvToBean like this:
CsvToBean<AccountBean> csvToBean = new CsvToBeanBuilder<AccountBean>(new InputStreamReader(inputStream))
.withFieldAsNull(CSVReaderNullFieldIndicator.NEITHER)
.withType(AccountBean.class)
.build();
And this is my AccountBean:
public class AccountBean extends BeanBase<Account>
{
#CsvBindByName(column = "Id", required = true)
public String salesforceId;
#CsvBindByName(column = "OwnerId", required = true)
public String ownerId;
#CsvBindByName(column = "Name", required = true)
public String name;
// billing address
#CsvBindByName(column = "BillingStreet")
String billingStreet;
#CsvBindByName(column = "BillingCity")
String billingCity;
#CsvBindByName(column = "BillingState")
String billingState;
#CsvBindByName(column = "BillingPostalCode")
String billingPostcode;
#CsvBindByName(column = "BillingCountry")
String billingCountry;
}
The issue is with the address fields - if there is a blank field, they are ALWAYS null, regardless of which CSVReaderNullFieldIndicator value I pass to .withFieldAsNull().
My csv file has double quotes to denote an empty field, so using CSVReaderNullFieldIndicator.NEITHER (which is default anyway) should produce an empty String.
This is causing issues as I'm saving nulls to my datastore and then it's causing NullPointerExceptions later.
An I doing something wrong?
I was trying your approach and I had the same behavior. Since this library is opensource I was digging to find why it happens.
Inside CsvToBean Class you have a CSVReader that is responsible for
access the data to be read.
Inside CSVReader you have a CSVParser which is responsible for take a single string and parse it into its elements based on the delimiter, quote and escape characters.
The CSVParser contains a member of CSVReaderNullFieldIndicator (enum) that is used to tell CSVParser what to consider null.
When you call build() in your code CsvToBean, CSVReader and CSVParser are instantiated based on the info that you passed to the CsvToBeanBuilder.
When you call parse() CSVReader will go through your CSV file and for each line it will call CSVParser. Based on your separator, the parser will return a String array of values. At this point the CSVParser, based on NullFieldIndicator, will consider to leave the string as empty or put it as null. At the end, if you have NullFieldIndicator property as NEITHER and the line considered is, for example, "one";"", the string array returned by the parser will be [one,""] or [one, null] if CSVReaderNullFieldIndicator is BOTH or EMPTY_QUOTES.
After this phase, the parsed line will be mapped to AccountBean fields. To decide either the field is null StringUtils.isNotBlank() is used.
Conclusion: No matter what you pass to withFieldAsNull(), because "" or null is considered to be false by StringUtils.isNotBlank(), therefore the field will be null.
You can ask the developer if this behavior was the expected one. Maybe he has a reason for it or it's just a bug.
This is going to require some thought as the issue is in BeanFieldPrimitiveTypes class which will only set a value if there is a value (so empty fields will result in a null). This is because this is is converting to all types and most do not handle empty strings (Integer). So this class needs to be modified to check the type of the field and if it is a certain set of types (String for now) then allow an empty value to be converted.
I posted the above in the bug you opened up in sourceforge and we will try and get a fix in either 4.1 or 4.2 of openCSV.

Design for large scale parameter validation for JPA?

I have a method that takes in a JSON and takes out the data and distributes it to various strings so that they can be set in an entity and persisted. My example below is quite simple but for my actual code I have about 20+ fields
For example see
public Projects createProject(JsonObject jsonInst) {
Projects projectInst = new Projects();
String pId = jsonInst.get("proId").getAsString();
String pName = jsonInst.get("proName").getAsString();
String pStatus = jsonInst.get("proStatus").getAsString();
String pCustId = jsonInst.get("proCustId").getAsString();
String pStartDate = jsonInst.get("proStartDate").getAsString();
...
//Set the entity data
projectInst.setProjectId(pId);
projectInst.setProjectName(pName);
...
Notice if a varible dosent have a corrosponding entry in the Json this code will break with null pointer exception. Obviously I need to validate each parameter befopre calling .getAsString()
What is the best way to do this from a readability point of view I could create 2 varibles for each parameter and check and set for example.
if(jsonInst.get("proName")){
String pName = jsonInst.get("proName").getAsString();
}
Or should I wait for it to be set
if(!pName.isEmpty()){
projectInst.setName(pName)
}
...
Which of these do you think is the best parameter to use for preventing errors.
Is there a way to handle if something is set on a large scale so that I can reduce the amount of code I have to write before I use that varible?
You can create a method that will take field name as parameter and will return json value for that field :
private String getJSONData(String field,JsonObject json){
String data=null;
if(json.has(field)){
data=json.get(field).getAsString();
}
return data;
}
you can call this method for each of your field:
String pId = getJSONData("proId",jsonInst);
By this way you can not only escape NullPointerException, but also avoid code repetition.

Java Jackson receive key with null value [duplicate]

What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.

Convert empty string to null using javax.validation annotations

I have the following variable annotated for data validation:
#Size(min=8, max=16, message="the size of the parameter must be between 8 and 16")
private String param;
However, the param can be null. It is required that it be 8-16 chars long only if it is not null. The problem I face is if the client app (JSON API) supplies an empty string, I want to treat it as though it were not supplied at all, i.e. is null. I was wondering if there is an elegant way to do this using the javax.validation annotations, i.e. convert an empty string to null, as opposed to the plain Java way the way I'm doing it right now:
public void setParameter(String _param) {
if(_param != null && !_param.trim().isEmpty()){
this.param = _param;
} else {
this.param = null;
}
}
I would like to have a very simple setter:
public void setParameter(String _param) {
this.param = _param;
}
and have the is-empty-string boilerplate done by an annotation. Is there a way to do it?
You could can implement your own custom constraint validator.
see here. I've used this many times and works like a charm.
https://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-customconstraints.html
You would just need to set this condition (if null return "" or vice-versa) in the isValid method.

java.lang.IllegalArgumentException: invalid ObjectId [0]

I'm getting an java.lang.IllegalArgumentException: invalid ObjectId [0] when I try to do similar to the code below in one of my class.
String s = "0_abc";
--------
private ObjectId obj; [Instance variable]
public NewClass(String s){
String[] sarray = s.split("_");
obj = new ObjectId(sarray[0]);
}
What could be the possible reason for it to fail?
I assume ObjectId class is (org.bson.types.ObjectId) and it is used in the MongoDB Java driver.
What this exception means is that "0" cannot be pass as a value for the ObjectId construction.
Not every string is a correct ObjectId value. When ObjectId is initialized with the given string, validation is done. For example ObjectId requires string to have 24 characters. There are more constrains and you can find the complete validation source code in GitHub repo, in the method isValid().
If you want to create an ObjectId object with correct value you can create it using available factory method like this:
ObjectId obj = ObjectId.get()
This will create ObjectId with auto-generated value.
Unfortunately you have not sent the stacktrace but I think that the exception is thrown from constructor of your class ObjectId that does not allow sending 0 as an argument.

Categories

Resources