What we are doing - Annotation driven null and empty values check for Object.
How we are doing - Creating one annotation and putting that annotation on the variable declaration.
I am not sure what design pattern i need to use to make it work best
. Please suggest.
Annotation class -
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Test {
/**
* Message.
*
* #return the string
*/
public String message();
}
How we are declaring variable -
#Test(message="five message")
private String five;
How i am calling annotation processor -
Class<?> annotationClass = annotationTestinClass.getClass();
Field[] decalaredFieldsArray = annotationClass.getDeclaredFields();
List<String> lstString = new ArrayList<>();
parseFields(decalaredFieldsArray,annotationTestinClass,lstString);
How i am processing object -
public static List<String> parseFields(Field[] decalaredFieldsArray,Object obj,List<String> lstString){
Arrays.stream(decalaredFieldsArray).forEach(field ->{
field.setAccessible(true);
Test test = field.getDeclaredAnnotation(Test.class);
if(field.getType().isPrimitive() || field.getType().getName().equals("java.lang.String")){
if(field.isAnnotationPresent(Test.class)){
try {
System.out.println("field value is :"+field.get(obj));
System.out.println("field Name is :"+field.getName());
if(field.get(obj)== null || !StringUtils.isNoneBlank(field.get(obj).toString())){
lstString.add(test.message());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}else{
Field[] objectFields =null;
Object objValue = null;
try {
if(field.isAnnotationPresent(Test.class)){
objValue = field.get(obj);
if(objValue!=null){
objectFields = objValue.getClass().getDeclaredFields();
parseFields(objectFields, objValue, lstString);
}else{
System.out.println("Object value is -"+field.get(obj));
System.out.println("Messsage value is -"+test.message());
lstString.add(test.message());
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
return lstString;
}
Here Test.Class is repersenting my Test annotation.
Annotations don't work that way.
You can create custom annotations that get processed at compile time. But at compile time, very often, you might not be able to check that
#NotNull
private Whatever foo = someBar();
really leads to "not null". In other words: at compile time, no code behind #NotNull can really decide in all cases if the annotated variable will be really not null.
And at runtime, annotations ... are just that: Meta-Information!
Meaning: if you want annotations to have an effect at runtime, you need code that checks for annotations when doing things.
Example: you create #Persist.
And then you have a framework that "processes objects". And whenever that framework processes some object, it can check if that annotation is present, and if so "persist" that object.
In other words:
foo = bar;
will just assign bar to foo; and there is "no framework" in place that could check if foo is #NotNull annotated, and do something about that assignment if bar is null.
So, in order for you to be helpful, you need
That new annotation
Some sort of "processor" that works on objects; and checks if they are annotated; and if they are annotated, special things happen.
Related
I've created the annotation I want to put on some fields of a class.
I want the annotation to check one of two or more fields:
#Documented
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface OneOfFields {
}
For example - the class:
public class MyClassRq {
#OneOfFields
private String stringOne;
#OneOfFields
private String stringTwo;
}
If I create an HttpRequest with the body and set both fields, I want to get an exception, javax.validation exception is also possible.
What is the best way to write the validator?
Annotations can be processed in two phases:
At compile time (in this case through an Annotation Processor)
At runtime (in this case through reflection)
It depends on when you want to perform the check. Considering that it seems you want to check this at runtime (i.e. when you receive the object), then you could create a sample method that takes an object, scans all the fields of the object for the annotation #OneOfFields and if more than one is not null, then it throws an exception:
public static <T> T validate(T input) {
try {
int numberOfAnnotatedNonNull = 0;
for (Field field : input.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(OneOfFields.class) && (field.get(input) != null)) {
numberOfAnnotatedNonNull++;
if (numberOfAnnotatedNonNull > 1) {
throw new IllegalStateException("More than one field annotated by #OneOfFields has been set for this object");
}
}
}
return input;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not validate input object", e);
}
}
Sample usage:
MyClassRq myClassRq = validate(yourInput);
If the above yourInput of type MyClassRq is valid, then it will simply return the same object. Else, it will throw an exception.
Some notes:
Here I'm throwing as soon as I find more than one field which is non null. You may of course create a cleaner error message (for example by collecting all the fields which are illegally set and returning their names)
Here I'm throwing a standard IllegalStateException but you can (you should probably) create your own custom exception
Don't forget to check that T input is not null (if it is, my code will crash).
This is a sample usage of the standard Java Reflect API, there are several ways of reaching the same purpose (I've just shown you the most "readable")
This is a general issue/problem that I have come across. I wondered if anyone knows of any well suited design patterns or techniques.
private ExternalObject personObject;
private String name;
private int age;
private String address;
private String postCode;
public MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
.
.
. many more setters
}
The class above takes external objects from a queue and constructs MyBuilderClass objects.
A MyBuilderClass object is successfully built if all of the fields have been set to non-null non-empty values.
There will be many MyBuilderClass objects that cannot be built because data will be missing from the ExternalObject.
My problem, what is the best way to detect if an object has been correctly built?
I could check for null or empty values in the set methods and throw an exception. The problem with this approach is throwing exceptions is expensive and it will clogg the log files up because there will be many instances where an object cannot be built;
What other approaches could I use?
Correct me if I'm wrong: you are trying to find a good way to check if an object is valid, and if it is not, tell the client code about this without using an exception.
You can try a factory method:
private MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public static MyBuilderClass initWithExternalObject(ExternalObject obj) {
// check obj's properties...
if (obj.getSomeProperty() == null && ...) {
// invalid external object, so return null
return null;
} else {
// valid
MyBuilderClass builder = new MyBuilderClass(obj);
return builder.build();
}
}
Now you know whether an object is valid without using an exception. You just need to check whether the value returned by initWithExternalObject is null.
I wouldn't throw exceptions in cases that aren't exceptional. And as the only way for a constructor not to produce an object is to throw, you should not delay validation to the constructor.
I'd still recommend the constructor to throw if its results were to be invalid, but there should be a validation before that, so you don't even call the constructor with an invalid ExternalObject.
It's up to you if you want to implement that as a static method boolean MyBuilderClass.validate(ExternalObject) or by using the builder pattern with this validation.
Another approach for such a validation is to use java Annotations:
Make a simple annotaion class, let's say Validate:
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#interface Validate {
boolean required() default true;
}
then annotate the fields you want to be present as #Validate(required=true):
class MyBuilderClass {
private ExternalObject externalObject;
#Validate(required=true)
private String name;
#Validate(required=false) /*since it's a primitive field*/
private int age;
#Validate(required=true)
private String address;
#Validate(required=true)
private String postCode;
MyBuilderClass(ExternalObject externalObject) {
this.externalObject = externalObject;
build();
}
public void build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
}
//.
//.
//. many more setters
}
And then add this method in the MyBuilderClass class, in order to check if your Object is built correctly:
public boolean isCorrectlyBuilt() throws IllegalAccessException {
boolean retVal = true;
for (Field f : getClass().getDeclaredFields()) {
f.setAccessible(true);
boolean isToBeChecked = f.isAnnotationPresent(Validate.class);
if (isToBeChecked) {
Validate validate = f.getAnnotation(Validate.class);
if (validate.required()/*==true*/) {
if (f.get(this) == null) {
retVal = false;
break;
/* return false; */
}
}
}
}
return retVal;
}
Here is an example of use :
public static void main(String[] args) throws Exception {
ExternalObject personObject = new ExternalObject();
personObject.setAge(20);
personObject.setName("Musta");
personObject.setAddress("Home");
personObject.setPostCode("123445678");
MyBuilderClass myBuilderClass = new MyBuilderClass(personObject);
System.out.println(myBuilderClass.isCorrectlyBuilt());
}
Output : true because the object is correctly built.
This will allow you to choose the fields that you want to be in the structure by reflection, without bringing those inherited from a base class.
As this previous answer suggests, here are 2 options either of which should be added after you have tried to set the variables.
use reflection to check whether any of the variables are null. (As mentioned in comments this will check all fields in this object but be careful with fields in any superclasses).
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
perform a null check on each variable.
boolean isValidObject = !Stream.of(name, age, ...).anyMatch(Objects::isNull);
Previous answer
From what I've come across you could overwrite the equals method of your object and compare it with a valid example object. Its dirty and might only work in some cases.
Your approach is the best I could think of. Write a seperate method or class that has for example a static validate method. You could reuse it anywhere.
How can I iterate over the attributes of an object, with the attribute names provided in a list/array - NOT all attributes, like using reflection & getDeclaredFields().
public class MyClass
{
public type1 att1;
public type2 att2;
public type3 att3;
public MyClass(
att1="helo";
att2="bye";
att3="morning";
);
...
public void function()
{
String myStrings[];
myStrings = new String[] { "att2", "att3" };
MyClass myobject = new MyClass();
for(var in myStrings)
{
System.out.println(var);
System.out.println(myobject.var);
System.out.println();
}
}
}
Your question is somewhat ambiguous about using reflection. If you are OK with reflection, but want specific fields only without iterating over getDeclaredFields(), then the following code should work for you:
for (String var : myStrings) {
Field field = MyClass.class.getDeclaredField(var);
field.setAccessible(true);
System.out.println(var);
System.out.println(field.get(myObject));
System.out.println();
}
Note that this code works for private fields, too. Also, keep in mind that you'll have to handle exception associated with the reflection calls.
UPDATE: Exceptions thrown in this code.
MyClass.class.getDeclaredField(var) declares a checked NoSuchFieldException. You must handle it because obviously there is no mechanism to make sure that the fields in myString match an actual implementation of MyClass.
field.get(myObject) throws a checked IllegalAccessException if the field is inaccessible. Which it should not be because of field.setAccessible(true), but you still have to catch or re-throw the exception.
There are also unchecked exceptions you may want to handle. See the javadoc for details
java.lang.Class.getDeclaredField(String)
java.lang.reflect.AccessibleObject.setAccessible(boolean) inherited by java.lang.reflect.Field
java.lang.reflect.Field.get(Object)
You probably want to use some technology that builds on top of JavaBeans / BeanInfo. Apache Commons / BeanUtils is a good starting point here.
Please refer to this previous answer of mine for more info:
https://stackoverflow.com/a/5856982/342852
But if you just want to use fields, not bean properties, here's a Java 8 method to do so:
public static Map<String, Object> getFieldProperties(Object o, Collection<String> fields) {
Class<?> type = o.getClass();
return fields.stream().map(n -> {
try {
return type.getDeclaredField(n);
} catch (NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}).collect(Collectors
.toMap(
(Function<Field, String>) Field::getName,
(Function<Field, Object>) field -> {
try {
field.setAccessible(true);
return field.get(o);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}));
}
Unfortunately the checked exceptions make this more verbose than it would need to be.
I need to make sure that no object attribute is null and add default value in case if it is null. Is there any easy way to do this, or do I have to do it manually by checking every attribute by its getters and setters?
You can use reflection to iterate over the object's field, and set them. You'd obviously need some sort of mapping between types or even field names and required default values but this can be done quite easily in a loop. For example:
for (Field f : obj.getClass().getFields()) {
f.setAccessible(true);
if (f.get(obj) == null) {
f.set(obj, getDefaultValueForType(f.getType()));
}
}
[Update]
With modern Java, you can use annotations to set the default values for fields on a per class basis. A complete implementation might look like this:
// DefaultString.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface DefaultString {
String value();
}
// DefaultInteger.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface DefaultInteger {
int value();
}
// DefaultPojo.java:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class DefaultPojo {
public void setDefaults() {
for (Field f : getClass().getFields()) {
f.setAccessible(true);
try {
if (f.get(this) == null) {
f.set(this, getDefaultValueFromAnnotation(f.getAnnotations()));
}
} catch (IllegalAccessException e) { // shouldn't happen because I used setAccessible
}
}
}
private Object getDefaultValueFromAnnotation(Annotation[] annotations) {
for (Annotation a : annotations) {
if (a instanceof DefaultString)
return ((DefaultString)a).value();
if (a instanceof DefaultInteger)
return ((DefaultInteger)a).value();
}
return null;
}
}
// Test Pojo
public class TestPojo extends DefaultPojo {
#DefaultString("Hello world!")
public String stringValue;
#DefaultInteger(42);
public int integerValue;
}
Then default values for a TestPojo can be set just by running test.setDetaults()
You need to manually filter input to constructors and setters. Well... you could use reflection but I wouldn't advise it. Part of the job of constructors and setters is to validate input. That can include things like:
public void setPrice(double price) {
if (price < 0.0d) {
throw new IllegalArgumentException("price cannot be negative " + price);
}
this.price = price;
}
and
public void setName(String name) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
}
You could use wrapper functions for the actual check and throwing the exception.
Non-reflective solution for Java 8, without using a series of if's, would be to stream all fields and check for nullness:
return Stream.of(id, name).allMatch(Objects::isNull);
This remains quite easy to maintain while avoiding the reflection hammer.
This will return true for null attributes.
Maybe check Hibernate Validator 4.0, the Reference Implementation of the JSR 303: Bean Validation.
This is an example of an annotated class:
public class Address {
#NotNull
private String line1;
private String line2;
private String zip;
private String state;
#Length(max = 20)
#NotNull
private String country;
#Range(min = -2, max = 50, message = "Floor out of range")
public int floor;
...
}
For an introduction, see Getting started with JSR 303 (Bean Validation) – part 1 and part 2 or the "Getting started" section of the reference guide which is part of the Hibernate Validator distribution.
You can create a function that returns a boolean value and checks every attribute. You can call that function to do the job for you.
Alternatively, you can initialize the object with default values. That way there is no need for you to do any checking.
I don't have enough context to give you a correct answer, but I'll suggest you to make you code immutable as much as possible. Use public final fields. No more getters or setters : every field has to be defined by the constructor. Your code is shorter, more readable and prevents you from writing code with side effects.
It doesn't prevent you from passing null arguments to your constructor though... You can still check every argument as suggested by #cletus, but I'll suggest you to throw IllegalArgumentException instead of NullPointerException that doesn't give no new hint about what you've done.
Anyway, that's what I do as much as I can and it improved my code (readability, stability) to a great extend. Everyone in my team does so and we are very happy with that. We learned that when we try to write some erlang code where everything is immutable.
Hope this helps.
I tried this and it works without any issues to validate if the field is empty.
I have answered your question partially as I haven't personally tried to add default values to attributes
if(field.getText()!= null && !field.getText().isEmpty())
Hope it helps
This is not to check for null, instead this will be helpful in converting an existing object to an empty object(fresh object). I dont know whether this is relevant or not, but I had such a requirement.
#SuppressWarnings({ "unchecked" })
static void emptyObject(Object obj)
{
Class c1 = obj.getClass();
Field[] fields = c1.getDeclaredFields();
for(Field field : fields)
{
try
{
if(field.getType().getCanonicalName() == "boolean")
{
field.set(obj, false);
}
else if(field.getType().getCanonicalName() == "char")
{
field.set(obj, '\u0000');
}
else if((field.getType().isPrimitive()))
{
field.set(obj, 0);
}
else
{
field.set(obj, null);
}
}
catch(Exception ex)
{
}
}
}
I need to make sure that no object attribute is null and add default value in case if it is null. Is there any easy way to do this, or do I have to do it manually by checking every attribute by its getters and setters?
You can use reflection to iterate over the object's field, and set them. You'd obviously need some sort of mapping between types or even field names and required default values but this can be done quite easily in a loop. For example:
for (Field f : obj.getClass().getFields()) {
f.setAccessible(true);
if (f.get(obj) == null) {
f.set(obj, getDefaultValueForType(f.getType()));
}
}
[Update]
With modern Java, you can use annotations to set the default values for fields on a per class basis. A complete implementation might look like this:
// DefaultString.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface DefaultString {
String value();
}
// DefaultInteger.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface DefaultInteger {
int value();
}
// DefaultPojo.java:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class DefaultPojo {
public void setDefaults() {
for (Field f : getClass().getFields()) {
f.setAccessible(true);
try {
if (f.get(this) == null) {
f.set(this, getDefaultValueFromAnnotation(f.getAnnotations()));
}
} catch (IllegalAccessException e) { // shouldn't happen because I used setAccessible
}
}
}
private Object getDefaultValueFromAnnotation(Annotation[] annotations) {
for (Annotation a : annotations) {
if (a instanceof DefaultString)
return ((DefaultString)a).value();
if (a instanceof DefaultInteger)
return ((DefaultInteger)a).value();
}
return null;
}
}
// Test Pojo
public class TestPojo extends DefaultPojo {
#DefaultString("Hello world!")
public String stringValue;
#DefaultInteger(42);
public int integerValue;
}
Then default values for a TestPojo can be set just by running test.setDetaults()
You need to manually filter input to constructors and setters. Well... you could use reflection but I wouldn't advise it. Part of the job of constructors and setters is to validate input. That can include things like:
public void setPrice(double price) {
if (price < 0.0d) {
throw new IllegalArgumentException("price cannot be negative " + price);
}
this.price = price;
}
and
public void setName(String name) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
}
You could use wrapper functions for the actual check and throwing the exception.
Non-reflective solution for Java 8, without using a series of if's, would be to stream all fields and check for nullness:
return Stream.of(id, name).allMatch(Objects::isNull);
This remains quite easy to maintain while avoiding the reflection hammer.
This will return true for null attributes.
Maybe check Hibernate Validator 4.0, the Reference Implementation of the JSR 303: Bean Validation.
This is an example of an annotated class:
public class Address {
#NotNull
private String line1;
private String line2;
private String zip;
private String state;
#Length(max = 20)
#NotNull
private String country;
#Range(min = -2, max = 50, message = "Floor out of range")
public int floor;
...
}
For an introduction, see Getting started with JSR 303 (Bean Validation) – part 1 and part 2 or the "Getting started" section of the reference guide which is part of the Hibernate Validator distribution.
You can create a function that returns a boolean value and checks every attribute. You can call that function to do the job for you.
Alternatively, you can initialize the object with default values. That way there is no need for you to do any checking.
I don't have enough context to give you a correct answer, but I'll suggest you to make you code immutable as much as possible. Use public final fields. No more getters or setters : every field has to be defined by the constructor. Your code is shorter, more readable and prevents you from writing code with side effects.
It doesn't prevent you from passing null arguments to your constructor though... You can still check every argument as suggested by #cletus, but I'll suggest you to throw IllegalArgumentException instead of NullPointerException that doesn't give no new hint about what you've done.
Anyway, that's what I do as much as I can and it improved my code (readability, stability) to a great extend. Everyone in my team does so and we are very happy with that. We learned that when we try to write some erlang code where everything is immutable.
Hope this helps.
I tried this and it works without any issues to validate if the field is empty.
I have answered your question partially as I haven't personally tried to add default values to attributes
if(field.getText()!= null && !field.getText().isEmpty())
Hope it helps
This is not to check for null, instead this will be helpful in converting an existing object to an empty object(fresh object). I dont know whether this is relevant or not, but I had such a requirement.
#SuppressWarnings({ "unchecked" })
static void emptyObject(Object obj)
{
Class c1 = obj.getClass();
Field[] fields = c1.getDeclaredFields();
for(Field field : fields)
{
try
{
if(field.getType().getCanonicalName() == "boolean")
{
field.set(obj, false);
}
else if(field.getType().getCanonicalName() == "char")
{
field.set(obj, '\u0000');
}
else if((field.getType().isPrimitive()))
{
field.set(obj, 0);
}
else
{
field.set(obj, null);
}
}
catch(Exception ex)
{
}
}
}