Let's say I have a 10 unique POJOs each with 10 uniquely named fields.
This POJO is a deserialized SOAP response. I want to "copy" the fields from the SOAP POJOs over to a POJO that represents a JSON object, and then serialize that POJO.
Let's name our SOAP objects o0 ... o9
Let's name our SOAP fields f0 ... f9
Let's name our JSON object jo
Let's name our JSON fields f0 ... f99
Finally, all fields are containers for values, so each field has a .getValue() method.
Assuming all our fields have getters and setters, the only way to do this, from my understanding, is hardcoding the following:
jo.setF0(o0.getF0().getValue());
jo.setF1(o0.getF1().getValue());
...
jo.setF49(o4.getF9().getValue());
...
jo.setF99(o9.getF9().getValue());
Now, the problem is that any of the fields belonging to o0 ... o9 MAY be null, which will cause a NullPointerException.
Is there any way to get around this without writing 100 try/catch blocks?
maybe you can prevent nullPointer, testing if object is null before set value.
o0.getF0!=null ? o0.getF0().getValue(): null;
take a look to some framework like https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html to copy properties.
Here is a naive implementation of e bean value copier that copies all non-null properties that are present in both source and target:
public class BeanValueCopier {
static final Map<Class<?>, Map<String, PropertyDescriptor>> beanPropertiesByType = new ConcurrentHashMap<>();
public static void copyNonNullValues(Object src, Object dest) {
try {
Map<String, PropertyDescriptor> sourceMap = propertyMap(src.getClass());
Map<String, PropertyDescriptor> targetMap = propertyMap(dest.getClass());
for (Map.Entry<String, PropertyDescriptor> entry : sourceMap.entrySet()) {
final String propertyName = entry.getKey();
if (targetMap.containsKey(propertyName)) {
final PropertyDescriptor sourceDesc = entry.getValue();
final PropertyDescriptor targetDesc = targetMap.get(propertyName);
if (targetDesc.getPropertyType().equals(sourceDesc.getPropertyType()) && sourceDesc.getReadMethod() != null && targetDesc.getWriteMethod() != null) {
final Object value = sourceDesc.getReadMethod().invoke(src);
if (value != null) targetDesc.getWriteMethod().invoke(dest, value);
}
}
}
} catch (InvocationTargetException | IllegalAccessException | IntrospectionException e) {
throw new IllegalStateException(e);
}
}
private static Map<String, PropertyDescriptor> propertyMap(Class<?> beanClass) throws IntrospectionException {
Map<String, PropertyDescriptor> beanProperties = beanPropertiesByType.get(beanClass);
if (beanProperties == null) {
beanProperties = new HashMap<>();
for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(beanClass, Object.class).getPropertyDescriptors()) {
beanProperties.put(propertyDescriptor.getName(), propertyDescriptor);
}
beanPropertiesByType.put(beanClass, beanProperties);
}
return beanProperties;
}
}
Obviously this still has a lot of issues: Concurrency, handling of primitive types, exception handling etc., but it should get you started
This uses the JavaBeans Introspector mechanism
Related
I've two objects objclient and objserver of the same type Object,(i.e. Dog, Cat..)
when I receive objclient in my endpoint I need to replace its attributes with the non-null ones in objserver without doing explicitly, for example :
private void eraser(Object clientObject, Object serverObject){
//set only non null attributes of serverObject to clientObject
}
You can use e.g. ModelMapper if you want to map values between different java objects without explicitly having to map every single field.
BeanUtils.copyProperties is very common in spring-boot projects, we can use it with passing ignoreProperties (null case) & we can find the null case by using a custom method like below:
private ClientObject eraser(ClientObject clientObject, ServerObject serverObject){
BeanUtils.copyProperties(serverObject, clientObject, getNullPropertyNames(serverObject));
return clientObject;
}
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
It will set only non null attributes of serverObject to clientObject.
Actually the best solution comparing to #Rakib's one is:
private void erase(Object clientObject, Object defaultObject) throws IllegalAccessException, NoSuchFieldException {
Field[] Fields = defaultObject.getClass().getDeclaredFields();
for (Field field : Fields) {
field.setAccessible(true);
Object value = field.get(defaultObject);
if(value !=null)
field.set(clientObject,value);
}
}
I have a list of poperties defined in a config file, but before I proceed with further computations I would like to check if the properties have consistent values. Currently I am just doing via ifs.
private static void checkprops (Properties properties) throws Throwable {
if (!properties.getProperty("number").equals("one")
&& !properties.getProperty("number").equals("two")) {
throw new Exception("ERROR");
}
if (!properties.getProperty("check").equals("false")
&& !properties.getProperty("check").equals("true")) {
throw new Exception("ERROR");
}
if (properties.getProperty("totalnum").equals("null")) {
throw new Exception("ERROR");
}
}
Is there any way to do it somehow shorter and easier to read, since I have some properties that will have 5-6 different options.
First of all let me point out, that your code has an error:
if (properties.getProperty("totalnum").equals("null")) { ... }
If the property is not defined, getProperty() returns null, thus your code would raise a NullPointerException when trying to access equals(). It does not return a string with value "null". That's the case for all your lines.
I'd approach this using reflection, with a config class that declares public fields that might be annotated with value checks. A method will then set values on an instance of that config class, reading from the properties map.
Further reading:
What is reflection and why is it useful? (Stackoverflow)
Tutorial on Reflection (Oracle)
Article on Reflection (Oracle)
Tutorial on Annotations (Oracle)
The advantage of this is that the config shows the valid values in an intuitive, speaking format. The drawback is that the "unmarshalling" code is a bit complex. though this approach is quite powerful.
The config could look like this:
static class Config {
#RegExp("^(one|two)$")
public String number;
public Boolean check;
#Required #Range(min=1, max=6)
public Integer totalnum;
}
If a field is lacking the #Required annotation, a missing property does not result in an exception, thus the initialization value of Config is used.
Unmarshalling is done using this:
Config config = new Config();
setProperties(properties, config);
setProperties() will throw several exceptions when values are missing, have the wrong type or value. The exception can be catched and differentiated to display proper error messages.
In you application you can then access the config like simple objects:
if (config.totalnum == 3) {
// do something when totalnum is 3
}
This is the unmarshalling code:
private void setProperties(Properties properties, Props props) throws SecurityException, IllegalArgumentException, IllegalAccessException {
Class<?> clazz = props.getClass();
for (Field field : clazz.getDeclaredFields()) {
if ((field.getModifiers() & Modifier.PUBLIC) == 0) {
// ignore non-public properties
continue;
}
// the type of the field
Class<?> fieldType = field.getType();
// the field name of the class
String fieldName = field.getName();
// the raw value loaded from the .properties file
String value = properties.getProperty(fieldName);
// fields may be annotated with #Required
boolean required = (field.getAnnotation(Required.class) != null);
if (required && value == null) {
// field required but not defined in the properties, fail
throw new IllegalArgumentException(
String.format(
"Field %s is required",
fieldName
)
);
} else if (value == null) {
// ignore undefined field, default to class initialized value
continue;
}
// checks per type follow ...
if (fieldType == String.class) {
// fields may be annotated with RegExp to specify a matcher
RegExp regExp = field.getAnnotation(RegExp.class);
if (regExp != null && !Pattern.matches(regExp.value(), value)) {
throw new IllegalArgumentException(
String.format(
"Value for field %s does not match %s: %s",
fieldName,
regExp.value(),
value
)
);
}
field.set(props, value);
} else if (fieldType == Integer.class) {
// may throw NumberFormatException if not a valid integer
Integer intValue = Integer.parseInt(value);
// fields may be annotated with Range to specify an integer range
Range range = field.getAnnotation(Range.class);
if (range != null && !(intValue >= range.min() && intValue <= range.max())) {
throw new IllegalArgumentException(
String.format(
"Value for field %s out of range (%d..%d): %d",
fieldName,
range.min(),
range.max(),
intValue
)
);
}
field.set(props, intValue);
} else if (fieldType == Boolean.class) {
// strictly check valid boolean values
if (!Pattern.matches("^(true|false)$", value)) {
throw new IllegalArgumentException(
String.format(
"Value for field %s is not a valid boolean (true|false): %s",
fieldName,
value
)
);
}
field.set(props, Boolean.parseBoolean(value));
}
}
}
Though already quite complex this code is rather simple. It does not handle other number types like Long or primitive types like int yet. These can be implemented using further if branches.
These are the annotations (defined in separate classes):
#Retention(RUNTIME)
#Target(FIELD)
public #interface Range {
public int min() default Integer.MIN_VALUE;
public int max() default Integer.MAX_VALUE;
}
#Retention(RUNTIME)
#Target(FIELD)
public #interface RegExp {
public String value() default "^.*$";
}
#Retention(RUNTIME)
#Target(FIELD)
public #interface Required {
}
You can create a utility method that would accept value from your configuration file and expected values as parameter and return a bool, for example:
public boolean validateProp(T propVal, T... expectedVals) {
for(T expectedVal : expectedVals) {
if(propVal == null) {
if(expectedVal == null) {
return true;
}
}
else if(propVal.equals(expectedVal)) {
return true;
}
}
return false;
}
A sample call in that case would be:
if(!validateProp(properties.getProperty("number"), "one", "two") {
throw new Exception("ERROR");
}
An option to avoid validating the Properties object directly is to map it to a POJO and then use Bean Validation on it.
Bean Validation is a standard Java API for specifying validation constraints and checking objects (or even method arguments) for validity, which relieves you from writing much of the code for modeling errors.
The reference implementation is Hibernate Validator but, despite the name, you can use it standalone without using all of Hibernate.
As an example (which might need some additional work):
public class Config {
#Pattern("^(one|two)$")
private String number;
#NotNull
private Boolean check;
#NotNull
#Min(1)
#Max(6)
private Integer totalnum;
public static Config fromProperties(Properties ps) {
Config conf = new Config();
conf.number = ps.getProperty("number");
// fails right away if "check" is null
conf.check = Boolean.valueOf(ps.getProperty("check"));
// fails right away if "totalnum" is null
conf.totalnum = Integer.valueOf(ps.getProperty("totalnum"));
return conf;
}
}
And the calling code:
Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
Config config = Config.fromProperties(properties);
Set<ConstraintViolation<Config>> violations = validator.validate(config);
if (violations.isEmpty()) {
// good to go
} else {
// some code to print the errors
}
In the example, I'm using the #Pattern constraint to match using a regex but, since you mentioned some properties have 5-6 possible values, it might be better to define your own annotation like
#Values({"one", "two", "three", "four"})
private String number;
I would like to have a method to validate fields kind of
protected void validate(String field, String fieldName){
if (field==null || field.isEmpty){
throw new IllegalArgumentException("Parameter " + fieldName + " cannot be empty");
}
}
and use in my class for example
class Foo {
private String x;
private String y;
...
public void validateAll(){
validate(x, "x");
validate(y, "y");
}
}
It would be great to use in this way
public void validateAll(){
validate(x);
validate(y);
}
and let the compiler pass the name of the variable automatically to validate(field, fieldName) method
How can I achive this in Java-8 ?
You can achieve this in Java by abandoning the idea of having java classes with fields, and instead having a Map which maps Column objects to values. From a usage standpoint, it would look roughly like this:
public static final Column<String> X_COLUMN = new Column<>( "x", String.class );
public static final Column<String> Y_COLUMN = new Column<>( "y", String.class );
public static final Table FOO_TABLE = new Table( "Foo", X_COLUMN, Y_COLUMN, ... );
...
Row fooRow = new Row( FOO_TABLE );
fooRow.setFieldValue( X_COLUMN, "x" );
String x = fooRow.getFieldValue( X_COLUMN );
for( Column<?> column : fooRow.getTable().getColumns() )
doSomethingWithField( fooRow, column );
private static <T> void doSomethingWithField( Row row, Column<T> column )
{
T value = row.getFieldValue( column );
...do something with the field value...
}
Since a value passed as argument to a method bears no information about the field it originated from, if it was read from a field at all, you can’t reconstruct this information. However, since your intent to verify fields, the desired operation is possible when processing the fields in the first place, rather than their contained values:
class Foo {
private String x;
private String y;
//...
public void validateAll() {
for(Field f: Foo.class.getDeclaredFields()) {
if(!Modifier.isStatic(f.getModifiers()) && !f.getType().isPrimitive()) try {
Object o=f.get(this);
if(o==null || o.equals(""))
throw new IllegalArgumentException(f.getName()+" cannot be empty");
} catch(ReflectiveOperationException ex) { throw new AssertionError(); }
}
}
}
The general problem of this approach is that by the time validateAll() reports a problem, the Foo instance already contains the illegal state. It’s preferable to reject invalid values right when they are attempted to set for a property. In that case, the parameter name of the method might not be available reflectively, however, when a method named setX throws an IllegalArgumentException (as would be indicated by the stack trace), there is no need for an additional meta information in the message…
I have a class
Class Test{
private String something ;
private String somethingElse;
private String somethingMore;
}
I am creating an instance of this.
myInst = new Test();
and adding values to first and second variables.
Now I need to check if any of the variable is null.
I know I can do this like if(myInst.something == null)
but for each item I add to the class it's difficult to do.
Is there anyway that i can check the instance by looping through all elements and seeing anything is null.
just like -
for(i=0; i< myInstanceVariables ; i++)
{
if(myInstanceVariable == null ){
//do something
donotDisplay(myInstanceVariable)
}
TIA
You can use Reflection using Fields from your instance. In your class, add this code. It will take all the fields and get their value.
Field[] fields = getClass().getDeclaredFields(); // get all the fields from your class.
for (Field f : fields) { // iterate over each field...
try {
if (f.get(this) == null) { // evaluate field value.
// Field is null
}
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
Here is a sample code: https://ideone.com/58jSia
You have to use reflection over Field of the Class.
myInst = new Test();
for (Field field : myInst.getClass().getDeclaredFields())
if (field.get(myInst) == null)
// do something
You can use reflection, however, in your case you only have String values, and thus it would also make sense to use a HashMap (for instance):
HashMap hm = new HashMap();
hm.put("something", "itsValue");
hm.put("somethingElse", null);
Now you can put as many values as you would like, and iterate through them like this:
Set set = hm.entrySet();
Iterator i = set.iterator();
while(i.hasNext()){
Map.Entry me = (Map.Entry)i.next();
System.out.println(me.getKey() + " : " + me.getValue() );
}
Is there any way to cast the value of a Java HashMap to an Object at runtime like this:
claas Foo {
public int a;
public String b;
}
Foo foo = new Foo();
HashMap<String, Object> map = new HashMap<String, Object>();
for(Map.Entry<Foo, Bar> entry : map.entrySet()) {
String propertyName foo = entry.getKey();
Object o = entry.getValue();
foo[propertyName] = o; // Does not wokring
}
I tryed to parse a SQL-Query result to a object. Now i've written my own Seralize-Algorithm. Bot it doesn't work. Is there a better way to Unerialize Object from the Database?
Connection connection = DriverManager.getConnection(instance);
PreparedStatement statment = connection.prepareStatement("SELECT * FROM Foo;");
Foo data;
ResultSet rs = statment.executeQuery(query);
if (rs != null && rs.next()) {
for (Field field : data.getClass().getDeclaredFields()) {
try {
if ((String.class.equals(field.getType()))) {
field.set(String.class, rs.getString(field.getName()));
} else if ((Boolean.class.equals(field.getType()))) {
field.set(Boolean.class, rs.getBoolean(field.getName()));
} else if ((Integer.class.equals(field.getType()))) {
field.set(Integer.class, rs.getInt(field.getName()));
}
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
It sounds like what you're actually trying to ask is:
Is there any way of accessing a variable dynamically by name at execution time?
To which the answer is "yes, but it's usually a bad idea".
You can use reflection:
Field field = Foo.class.getDeclaredField(entry.getKey());
field.set(foo, entry.getValue());
But it will be slow, and you'll only find out about invalid keys/values at execution time. It's generally a bad idea. If you only know things dynamically, you can keep them dynamic - keep them in the map. If you want to store arbitrary properties, there's usually a better way of approaching the problem (e.g. custom serialization) but without more details, we can't help you work out that better way.
(Also note that you'll need Map.Entry<String, Object>, not Map.Entry<Foo, Bar> for your entry variable.)