RazorAlliance192
RazorAlliance192

Reputation: 752

Duplicate and add fields between classes

I was wondering if the following scenario is possible.

Having two classes (Source and Destination) where in 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 here is that I have two classes, one called Source that contains (private) fields and one called Destination with no fields. After creating two objects of these classes and passing in Source into the constructor of Destination, I want to be able to duplicate/copy the fields of Source into Destination.

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

Upvotes: 3

Views: 880

Answers (5)

wassgren
wassgren

Reputation: 19231

A hackish version to accomplish this is to add all fields to a Map. The fields can be copied from the source object to the destination object and the field name can be the key. Something along the lines of this:

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());
        });
    }
}

For more info, check out this SO.

However, this is not something I would use in real production code. Instead, I would use some sort of serialization by e.g. using Jackson.

Upvotes: 3

Serge Ballesta
Serge Ballesta

Reputation: 149175

So you want to dynamically create fields in an object ? That's not directly possible in Java. If you just wanted to copy methods of an interface, the answer would have be to use a JDK proxy. It may still be of interest if :

  • you accept to only use getters and setters in Destination class
  • Source class implements an interface defining the setters and getters you want to copy

If you cannot accept those restrictions, you will have to look to CGLIB proxies or Javassist, that is libraries that dynamically modify the bytecode of the compiled class objects at load time. It is a really advanced feature, that is mainly used in frameworks or other libraries and not in high-level programs. Typically it is used in Object Relational Mappers like Hibernate to replace simple collection classes with enhanced ones that transparently gets (an save) their elements in database.

In any other case, trying to access private fields outside of the class should be seen as an indicator for a possible design flaw. private means implementation dependant and can change across versions and should not be used without knowing why.

Upvotes: 1

void
void

Reputation: 7890

The only thing is in my mind for this at this time is extending Destination class from Source

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");

Upvotes: 0

Eran
Eran

Reputation: 394136

The simplest and most efficient way to do it is copying the fields explicitly :

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

I don't see the point in using reflection for this purpose.

Upvotes: 0

Neha Agrawal
Neha Agrawal

Reputation: 155

Private members of Source cannot be accessed from Destination object even if you are passing a Source object to Destination.

You need to add string fieldA, fieldB to Destination to

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

Upvotes: -2

Related Questions