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);
}
}
Related
I am trying to create a utility method that should be able to deep-clone any object.
(Object.clone() only works on Object implementing Cloneable and I heard it's flawed anyways.)
I am using Objenesis to create new instances of objects without the use of constructors.
However, when trying to clone a JFrame I get the following Exception:
(using this class because I think it should be a good and complex test)
java.lang.InstantiationError: [Ljava.util.concurrent.ConcurrentHashMap$Node;
at sun.reflect.GeneratedSerializationConstructorAccessor12.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
I am open to any solution, not necessarily limited to Objenesis.
My Code:
private static ObjenesisStd OBJENESIS = new ObjenesisStd();
#SuppressWarnings("unchecked")
public static <T> T clone(T object, boolean deep){
if(object == null){
return null;
}else{
try {
T clone = (T) OBJENESIS.newInstance(object.getClass());
List<Field> fields = ReflectionUtil.getAllFieldsInHierarchy(object.getClass());
for(Field field : fields){
boolean isAccessible = field.isAccessible();
boolean isFinal = ReflectionUtil.isFinal(field);
field.setAccessible(true);
ReflectionUtil.setFinal(field, false);
Class<?> type = field.getType();
if(!deep || type.isPrimitive() || type == String.class){
field.set(clone, field.get(object));
}else{
field.set(clone, clone(field.get(object), true));
}
field.setAccessible(isAccessible);
ReflectionUtil.setFinal(field, isFinal);
}
return clone;
} catch (Throwable e) {
e.printStackTrace();
//throw new RuntimeException("Failed to clone object of type " + object.getClass(), e);
return null;
}
}
}
public static void main(String[] args) {
GetterSetterAccess access = new GetterSetterAccess(JFrame.class);
JFrame frame = new JFrame("Test Frame");
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
System.out.println("----------------------------------------------");
frame = clone(frame, true);
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
}
EDIT: Got it to work with the accepted answer and a few more fixes:
Avoided cloning Wrappers of Primitive Types (Integer.class etc.)
Avoided cloning Classes (Objects of the class Class.class)
Stored the cloned objects in a Map and reused them, so if Object A has a reference to Object B and Object B one to Object A it doesn't get stuck in an infinite loop. I also used a Map that checks for exact equality (==) instead of using equals().
Created a custom exception class which would just be passed on instead of throwing a new exception on every level (causing a huge caused-by-depth).
I finally figured it out. Your code doesn't handle arrays. So it fails with instantiating "[Ljava.util.concurrent.ConcurrentHashMap$Node;" which is an array of Nodes.
However, I will advocate that indeed, you should not do that. You will end up with fairly complicated code. Depending on what you want to do, you could use Jackson or XStream to do a marshall / unmarshall to perform the copy.
If you really want to continue that path, you will need something like this after the null check of your clone method.
if(object.getClass().isArray()) {
int length = Array.getLength(object);
Object array = Array.newInstance(object.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(array, i, clone(Array.get(object, i), true));
}
return (T) array;
}
I have an object, that might have other objects or list of objects. Is there a way to iterate through these objects to copy their values into a new object? What I want to do is merge 2 objects to update a document in my DB, so I don't want the null values.
So far I've reached the way to do a shallow copy with no nulls value for any object with this:
public Object merge(Object target) {
try {
Field[] fields = this.getClass().getDeclaredFields();
for (Field f: fields) {
if (f.get(this) != null) {
f.set(target, f.get(this));
System.out.println(f.get(this));
}
}
} catch (IllegalAccessException e) {
return target;
}
return target;
}
Problem Statement: But now, how can I handle nested objects? Like a List of Car objects for example?
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…
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
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() );
}