Duplicate and add fields between classes

I was wondering if the following scenario is possible.

Having two classes (source and destination) where in the code I could do this:

public class Source{

   private String fieldA;
   private String fieldB;

   public Source(){ ... }
}

...

public class Destination{

   public Destination(Source src){ ... }
}

Source src = new Source();
Destination dest = new Destination(src);
dest.fieldA = "test";
dest.fieldB = "test";

      

So what I mean is that I have two classes, one called Source

that contains (private) fields and one called Destination

without fields. After creating two objects of these classes and passing them in Source

in the constructor Destination

, I want to be able to duplicate / copy fields Source

in Destination

.

Could there be something like this in Java, whether or not using Reflection? And if possible can someone give me a small example where I can start.

+3


source to share


5 answers


To crack this version, you need to add all the fields to Map

. Fields can be copied from source to target and the field name can be a key. Something like that:

public class FieldAccessor {
    public static class Destination {
        private final Map<String, Object> fields = new HashMap<>();

        public Destination(Object o) {
            final Set<Field> accessibleFields = Arrays.stream(o.getClass().getDeclaredFields())
                    .map(field -> {
                        field.setAccessible(true);
                        return field;
                    })
                    .collect(Collectors.toSet());

            accessibleFields.forEach(field -> {
                try {
                    fields.put(field.getName(), field.get(o));
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Unable to access field", e);
                }
            });
        }

        public Set<String> fieldNames() {
            return fields.keySet();
        }

        public Optional<Object> fieldValue(String fieldName) {
            return Optional.ofNullable(fields.get(fieldName));
        }
    }

    public static class Source {
        private final String fieldA;
        private final Integer fieldB;
        private final int fieldC;

        public Source(String fieldA, Integer fieldB, int fieldC) {
            this.fieldA = fieldA;
            this.fieldB = fieldB;
            this.fieldC = fieldC;
        }

        public String getFieldA() {
            return fieldA;
        }

        public Integer getFieldB() {
            return fieldB;
        }

        public int getFieldC() {
            return fieldC;
        }
    }

    @Test
    public void testFields() {
        Destination destination = new Destination(new Source("Abc", 123, 456));

        destination.fieldNames().stream().forEach(fieldName -> {
            System.out.println("Fieldname: " + fieldName + ", value: " + destination.fieldValue(fieldName).get());
        });
    }
}

      



Check out this SO for more information .

However, this is not something I would use in real production code. I would use some serialization instead, eg. using Jackson .

+3


source


So you want to dynamically create fields in an object? This is not possible directly in Java. If you just want to copy interface methods, the answer would be to use a JDK proxy. It might be interesting if:

  • you agree to only use getters and setters in the class Destination

  • Source

    the class implements an interface that defines the setters and receivers you want to copy.


If you cannot accept these restrictions, you will have to look for CGLIB proxies or Javassist , that is, libraries that dynamically change the bytecode of compiled class objects at load time. This is a really advanced feature that is mostly used in frameworks or other libraries, not high-level programs. It is commonly used in Object Relational Mappers like Hibernate to replace simple extended class classes that transparently retrieve (store) their elements in the database.

In any other case, an attempt to access private fields outside the class should be considered an indicator of a possible design flaw. private tools are implementation dependent and can change from different versions and should not be used without knowing why.

+1


source


The easiest and most efficient way to do this is to copy the fields explicitly:

   public Destination(Source src)
   {
       this.fieldA = src.getFieldA();
       this.fieldB = src.getFieldB();
   }

      

I see no point in using reflection for this purpose.

0


source


The only thing I can object to is extending the Destination

classSource

public class Source{

   private String fieldA;
   private String fieldB;

   //You need to have both Getter and Setter for fieldA and fieldB

   public Source(){ ... }
}

...

public class Destination extends Source{

   public Destination(){...}
}

Source src =  new Destination();
dest.setFieldA("test");
dest.setFieldB("test");

      

0


source


The private members of the source cannot be accessed from the Destination object, even if you pass the Source object to the Destination.

You need to add the line fieldA, fieldB to Destination to

string fieldA, fieldB;
public Destination(Source src)
{
   fieldA = src.fieldA;
   fieldB = src.fieldB;
}

      

-2


source







All Articles