I have a VO similar to this.
public class Job
{
private Long id;
private String createdBy;
private Set<JobStatus> jobStatuses;
}
And many more similar fields. I want to iterate through the fields in VO and set 'NA' for all String fields which doesn't have data. This is what I have so far.
Job job = getJob();//getting the Job populated
BeanInfo beanInfo = Introspector.getBeanInfo(Job.class);
for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {
if (propertyDesc.getReadMethod().invoke(job) == null
&& propertyDesc.getPropertyType() == String.class) {
propertyDesc.getWriteMethod().invoke(job, "NA");
}}
This works well. But now I need to iterate through the other fields which are objects by itself and do the same dynamically. Like Set<JobStatus> jobStatuses. How can I do it ?
Frankly, this is just bad practice.
If you want to save your object in the database and want the empty attributes to be saved as 'NA' (for whatever reason) just set the default value for the column to 'NA'.
You can also initialize the object with attribute values = 'NA' in the constructor saves you much time that looping through the object properties.
If you don't initialize those variables in the constructor with N/A, you could also have a method on each object that sets the null variables to N/A and just call it.
You cannot assign string values to the Java objects that are not String types. But I am assuming it is ok for you assign an empty object constructed from a default constructor, if exists, to properties that are null. With that assumption, try the following solution:
for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {
if (propertyDesc.getReadMethod().invoke(job) == null
&& propertyDesc.getPropertyType() == String.class) {
propertyDesc.getWriteMethod().invoke(job, "NA");
}
else if (propertyDesc.getReadMethod().invoke(job) == null
&& propertyDesc.getPropertyType() != String.class) { //Other than String types
propertyDesc.getWriteMethod().invoke(job, propertyDesc.getPropertyType().newInstance());
}
}
Don't forget to handle this code with a try-catch block. Not all objects in your class might have a default constructor in which case you might want to further customize your code.
Related
Just for fun I wanted to try to implement a field by field, generic object comparator and this is what I did :
private Boolean isEqualFiedByField(Object o1, Object o2){
if (o1 == null || o2 == null || o1.getClass() != o2.getClass())
return false;
ObjectMapper mapper = new ObjectMapper();
Boolean result = true;
Map map1 = mapper.convertValue(o1, Map.class);
Map map2 = mapper.convertValue(o2, Map.class);
for (Object field : map1.keySet()) {
String fieldName = field.toString();
if (map1.get(fieldName) != null && map2.get(fieldName) != null)
result &= map1.get(fieldName).toString().equals(map2.get(fieldName).toString());
else
result &= (map2.get(fieldName) == map1.get(fieldName));
}
return result;
}
Is there anyway to improve this code ? Make it cleaner, faster or treat edges cases I forgot ?
Your current code uses ObjectMapper, you could also do this using reflection and not depend on any library. Not sure that's better, but something to consider.
I always put braces around blocks, even one-liners. You might later want to add a line to your if block and forget to add the braces.
You chose to handle the case with two null arguments by returning false. Is that a deliberate decision? You might want to put some JavaDoc on your method explaining this.
I think you could split your method into at least 3 parts, already indicated by empty lines in your current code. These parts do different things so could be handled in separate methods.
You are calling map1.get(fieldName) three times in your code (also map2). I would call it only once and assign the value to a local variable.
If you can get ObjectMapper (I don't know the class) to return a Map<String, Object> you can avoid all the toString calls later in the code.
I am parsing input JSON. For a field, there are 3 possibilities:
the field is absent;
the value is set to null;
the value is set to something valid.
Different behavior is implemented: for an absent value in the JSON, the default value is inserted into the database; for a null value in the JSON, a null value is inserted into the database.
I thought about Optional to model this:
public class Data {
private Optional<String> field;
}
Which of the following two options make most sense?
If field is null, the field was absent in the JSON. If field is Optional.empty, the field is null in the JSON.
If field is null, the field was null in the JSON. If field is Optional.empty, the field is absent in the JSON.
FWIW, I am using Jackson with module jackson-datatype-jdk8 to parse the input JSON.
I think you shouldn't use Optional for this scenario. As #dkatzel has mentioned in his answer, it's meant to be used as an API return value more than as a field.
Despite this academic discussion, you can accomplish what you want simply by initializing fields in your Data class to their default values:
public class Data {
private String field = DEFAULT_VALUE;
}
And then let Jackson do the rest.
EDIT as per OP's comment:
When your JSON comes with a null value for the field, Jackson will set it to null, and that's what will be stored in the database.
When your JSON does not contain the field, the DEFAULT_VALUE will be automatically loaded in your Data instance.
And when your JSON does actually contain a value for the field, Jackson will set it, and that value will reach the database.
EDIT 2, considering OP's requirement to find out if the field was either filled in, set to null or was absent in the input JSON, after parsing the JSON input:
If, after parsing the input JSON, you need to know whether the field was either filled in, set to null or was absent, then consider this example, which shows the approach I'd take:
public class Data {
private String field1 = "hello";
private Integer field2 = 10;
private Double field3 = 3.75;
private static final Data DEFAULTS = new Data(); // defaults will be kept here
public String getField1() {
return this.field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public Integer getField2() {
return this.field2;
}
public void setField2(Integer field2) {
this.field2 = field2;
}
public Double getField3() {
return this.field3;
}
public void setField3(Double field3) {
this.field3 = field3;
}
#Override
public String toString() {
return "Data [field1=" + this.field1 +
", field2=" + this.field2 +
", field3=" + this.field3 + "]";
}
public boolean isDefault(Function<Data, Object> getter) {
Object defaultProperty = getter.apply(DEFAULTS);
Object actualProperty = getter.apply(this);
return defaultProperty != null // needed to support fields with no default value
&& defaultProperty.equals(actualProperty);
}
public boolean isNull(Function<Data, Object> getter) {
return getter.apply(this) == null;
}
public boolean isSet(Function<Data, Object> getter) {
return !this.isNull(getter) && !this.isDefault(getter);
}
}
Here I've used a private static attribute to hold your Data's default values and 3 methods to query any field state (default, null or set). In order to determine which field to query, these methods receive a Function<Data, Object>, which are given a Data instance and return an Object that is supposed to be the desired field. (If you stop to think it, getters can be seen as functions that take the instance as input and return a specific field of the instance).
So later, when you need to know how a certain field arrived in your JSON input, just use those 3 query methods to find out:
ObjectMapper m = new ObjectMapper();
String json = "{\"field1\":null,\"field2\":20}";
Data data = m.readValue(json, Data.class);
System.out.println(data); // Data [field1=null, field2=20, field3=3.75]
System.out.println("field1 default ? " + data.isDefault(Data::getField1)); // false
System.out.println("field1 null ? " + data.isNull(Data::getField1)); // true
System.out.println("field1 set ? " + data.isSet(Data::getField1)); // false
System.out.println("field2 default ? " + data.isDefault(Data::getField2)); // false
System.out.println("field2 null ? " + data.isNull(Data::getField2)); // false
System.out.println("field2 set ? " + data.isSet(Data::getField2)); // true
System.out.println("field3 default ? " + data.isDefault(Data::getField3)); // true
System.out.println("field3 null ? " + data.isNull(Data::getField3)); // false
System.out.println("field3 set ? " + data.isSet(Data::getField3)); // false
I would say that the first option makes the most semantic sense. It also potentially allows for easier computation.
Where a field in java is null, it is implied that a value is missing, which matches the first option.
I suggest that you store these fields in a hash-map where the key is the JSON field name and the value is the JSON field's value. I also suggest you don't use an optional here (as it can add an unnecessary layer of complexity), and instead use either a null or non-null object in the hashmap.
HashMap<String, Value> jsonFields = new HashMap<String, Value>();
boolean hasField1 = false;
Value field1Value = null;
if(jsonFields.contains("field1"){ // It is present in the JSON file
field1Value = jsonFields.get("field1"); // "null" here would mean that the JSON field was set to "null"
hasField1 = true;
}
The second choice makes more sense to me. null means null and empty means not present.
However, Optional shouldn't really be used as a field. It's supposed to be used as an API return value.
Could you instead store the data in a Map that allows null values? And if the key (your field) isn't present in the map, then return Optional.empty ?
Neither? I would annotate my POJO fields with #DefaultValue(). Then your possibilities are a null value or a non-null value specified in JSON, or the default if the field was omitted from JSON. And you can then just persist the POJO without any special per-field analysis.
If you are dealing with Object instead of String, here's a solution I find elegant:
use Optional.empty(); if there is no value
use Optional.of(value) if there is a value
use Optional.of(specialValue) if the value is null
where specialValue is a static singleton you can easily test, for instance: ObjectUtils.NULL (from commons.lang).
Then you can easily test your optional:
if (optional.isPresent()) {
if (ObjectUtils.NULL.equals(optional.get())) {
// value is there and null
} else {
// value is there and not null
}
} else {
// value is not there
}
I'm trying to find an easy way to perform multiple null checks/ replacements in multiple variables in Java.
I have an object with about 20 String variables. In the constructor I want to check if any of the variable values are null. If they are null I want to replace them with an empty String. I could perform a series of if statements but I feel like there must be a cleaner way to do this.
Unless you want to resort to reflection (which I strongly discourage) your best bet is probably to create a helper method (return s == null ? "" : s) and do
field1 = nullToEmpty(field1);
field2 = nullToEmpty(field2);
...
If you already depend on Apache Commons or Guava you can use StringUtils.defaultString or Strings.nullToEmpty.
I agree with aioobe, using reflection is something you should avoid like the plague. But if you are blessed with a project where for example you have to mock a REST interface manually and the objects that come via this interface have tons of Integer, String, Double etc. inside I think you have no other choice.
Here is a generic method that replaces all null pointers it can find in an object with its scalar default values, fills String fields with an empty string and does so recursively if the objects it finds have a parameterless default constructor. Hope this helps other people in the same situation as well.
static void fillNullObjects(Object object) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
if (field.get(object) != null) {
continue;
}
else if (field.getType().equals(Integer.class)) {
field.set(object, 0);
}
else if (field.getType().equals(String.class)) {
field.set(object, "");
}
else if (field.getType().equals(Boolean.class)){
field.set(object, false);
}
else if (field.getType().equals(Character.class)) {
field.set(object, '\u0000');
}
else if (field.getType().equals(Byte.class)) {
field.set(object, (byte) 0);
}
else if (field.getType().equals(Float.class)) {
field.set(object, 0.0f);
}
else if (field.getType().equals(Double.class)) {
field.set(object, 0.0d);
}
else if (field.getType().equals(Short.class)) {
field.set(object, (short) 0);
}
else if (field.getType().equals(Long.class)) {
field.set(object, 0L);
}
else if (field.getType().getDeclaredFields().length > 0){
for (Constructor<?> constructor : field.getClass().getConstructors()) {
if (constructor.getParameterTypes().length == 0) {
field.set(object, constructor.newInstance());
fillNullObjects(field.get(object));
}
}
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
Check out Apache Commons' StringUtils
StringUtils.defaultString(yourString)
This replaces nulls with an empty String. Or you can define your own replacement:
StringUtils.defaultString(null, "foo") // returns "foo"
http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#defaultString(java.lang.String)
Store your variables in an array (or list, if you don't know exacty the number of variables but I don't think so) and loop over it
String[] variables;
//...
for(int i = 0; i < variables.length; i++)
if(variables[i] == null) variables[i] = "";
20 field variables sounds like an egregious case. You should try to avoid explicitly handling that many variables in any situation, or at least factor the code so they are only ever explicitly listed in one place.
A common pattern is to associate each variable with an enumeration, and use the enumeration as a key in a Map with type Enum -> String, or use the enumeration's ordinal as an index into a String array that is sized to the Enumeration value.
Like so:
public enum StringProperties {
TTL, RECVBUF, SENDBUF, RETRIES, ... ;
}
If you wanted explicit default values, you can couple an enumeration with a number of parameters:
public enum StringProperties {
TTL ("100"),
RECVBUF ("1024"),
SENDBUF ("1500"),
RETRIES ("10"),
...
;
public String getDefaultValue() { ... }
}
This strategy means that your code needs minimal modification if you need to add/remove a property, or change a default value.
In your (copy constructor?) case, you can loop over the enumeration values with something like:
for (StringProperties property : StringProperties.values()) {
if (obj.getProperty(property) != null) {
// handle present case
...
} else {
// handle default storage case
...
}
}
Or, like thomas said, you can use a String array on its own, but this assumes that you don't need a way to address each String.
public static String checkNull (String inputString){
if(inputString == null){
inputString = "";
}
return inputString;
}
And just call that whenever you want to check a string.
For each field use the standard Java method:
Objects.toString(field, "");
Avoid constructor with a large number of fields if possible. Use Builder instead (as suggested in Effective Java, Item 2: Consider a builder when faced with many constructor parameters).
I am receiving list of fields. Near About to 60 fields.
From that I have to check 50 fields that are they null or empty, if not then I ll have to add them also in DB table.
Right now I am doing it manually using if condition. I am just thinking to do so, not implemented still yet.
Is there any better option then it ?
My Code :
if(ValidateData.checkIsNullOrEmpty(command.getSubscriptionStartYear())){
}
if(ValidateData.checkIsNullOrEmpty(command.getSubscriptionPeriod())){
}
if(ValidateData.checkIsNullOrEmpty(command.getExpectedArrivalTimeOfIssues())){
}
.....
.....
if(ValidateData.checkIsNullOrEmpty(command.getMaxNoOfClaims())){
}
Here command is class which receives Data from source.
Here ValidateData is a class :
It's method definition :
public static boolean checkIsNullOrEmpty(Integer arg){
if(arg != null) return true;
return false;
}
public static boolean checkIsNullOrEmpty(String arg){
if(!arg.trim().equals("") || !arg.trim().equals(" ") || arg.trim() != null) return true;
return false;
}
If anyone guide me or suggest me that is there any better option available ??
create a function like this:
public static bool AllNull(object... something)
{
for(var v :something)
if(v!=null){
if(v instanceof Integer)
// do integer validation
}else
//Err msg
}
Then you could call it like this:
if (AllNull(obj1, obj2, obj3, obj4, obj5, obj6))
{
// ...
}
if you want to be specific, separate strings and integers and make separate function like this one for each type you need
Edit
as i understod from your comment, u don't know varargs
varargs are useful for any method that needs to deal with an
indeterminate number of objects. One good example is String.format.
if you can edit command, you can mark each field that you want to check null with #NotNull, then use java reflect api to get all fields marked with #NotNull, and check whether some fields null or not
I think best solution for your problem is using Java Reflect.
Here is sample code to validate all field of an instance by Java Reflect.
Example I have one instance(pojo) of object PojoObj.
PojoObj pojo = new PojoObj("one1", 2, null, 4, "five", "Six");
Validate all fields by Java Reflect.
Class<PojoObj> aClass = PojoObj.class;
Field[] fields = aClass.getDeclaredFields();
for(Field field : fields) {
Object value = field.get(pojo);
Object type = field.getType();
if(value == null) {
System.out.println(field.getName() + " is null");
} else {
System.out.println(field.getName() + " is instanceof " + type + " and value = " + value);
}
}
Output:
fieldOne is instanceof class java.lang.String and value = one1
fieldTwo is instanceof long and value = 2
fieldThree is null
fieldFour is instanceof int and value = 4
fieldFive is instanceof class java.lang.String and value = five
fieldSix is instanceof class java.lang.String and value = Six
for (int lstSize = 0; lstSize < obj.size(); lstSize++) {
if (obj.get(lstSize).getCuffSize() == null) {
obj.get(lstSize).setCuffSize("");
}
}
I have an ArrayList, where there are many items which has a value of null, can i set values as empty string, if my items in my List Object holds null value.
For instance:
While looping i am getting cuffSize as null, so i am setting it to empty String. But there are such many items in my Object which needs to be set like this. Is there any better way where can i set all the items in my object holding null value to empty string?
An enhanced for would get rid of all the get() calls:
for (MyObj elem : obj) {
if (elem.getCuffSize() == null) {
elem.setCuffSize("");
}
}
In Java 8 you will be able to do this in a cleaner way using Lambdas, but in Java 7 I don't know of a better way than looping.
Rather than setting many properties from null to empty string later I think its better to initialize those properties inside your class itself to empty String like this:
public class MyClass {
private String cuffSize = ""; // init to empty String here
private String somethingElse = ""; // init to empty String here
...
}
Then even if you don't call setters of cuffSize it will contain an empty String instead of null.
I would suggest you add a method in the class of your object. which do the null->"" logic.
The method could return the object reference, so that you could do it during adding it into your list. something like:
public Obj null2empty(){
field1=field1==null?"":field1;
field2=field2==null?"":field2;
field3=field3==null?"":field3;
....
return this;
}
list.add(obj.null2empty());
also possible to do it in iteration:
for(Obj obj : list) obj.null2empty();
Or you can use iterator:
Iterator<MyObject> it = obj.iterator();
while(it.hasNext())
{
MyObject obj = it.next();
if(obj == null) { .. }
}
The implementation of getCuffSize() method can be below, so that your end objective is met
public String getCuffSize()
{
return (cuffSize == null) ? "" : cuffSize;
}