3

I have 2 very similar JAXB objects Group with hundreds of fields, the only difference is that those object are in different packages, so the compiler prevents me of setting the value of another class. Here how it looks.

//employer sits in this package: com.beans.enrollment
      bodyResponse.setEmployer((com.beans.external.groupresponse.EmployerType)
sgCreateQuoteRequest.getRequest().getEmployer());

So I get compilation error here and It will take me tons of time to manually get/set those fields.

Any ideas how to cast these objects ?

user2508615
  • 213
  • 2
  • 16

7 Answers7

2

You could use the JAXB APIs to do the copy. This involves wrapping the source data in an instance of JAXBSource then since an Unmarshaller can unmarshal from a Source simply unmarshal the JAXBSource to get the data copied to the second model.

DEMO CODE

Demo

import javax.xml.bind.*;
import javax.xml.bind.util.JAXBSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        // Create Input from Foo Model
        forum17791487.foo.Root fooRoot = new forum17791487.foo.Root();
        fooRoot.setValue("Hello World");
        JAXBContext fooContext = JAXBContext.newInstance(forum17791487.foo.Root.class);
        JAXBSource jaxbSource = new JAXBSource(fooContext, fooRoot);

        // Unmarshal Foo Input to Bar Model
        JAXBContext barContext = JAXBContext.newInstance(forum17791487.bar.Root.class);
        Unmarshaller unmarshaller = barContext.createUnmarshaller();
        forum17791487.bar.Root barRoot = (forum17791487.bar.Root) unmarshaller.unmarshal(jaxbSource);
        System.out.println(barRoot.getValue());
    }

}

Output

Hello World

JAVA MODEL

The following classes only differ by package name. While only one class per package was used in this example the same principle applies for larger models.

forum17791487.foo.Root

package forum17791487.foo;

import javax.xml.bind.annotation.*;

@XmlRootElement
public class Root {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String foo) {
        this.value = foo;
    }

}

forum17791487.bar.Root

package forum17791487.bar;

import javax.xml.bind.annotation.*;

@XmlRootElement
public class Root {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String foo) {
        this.value = foo;
    }

}

FOR MORE INFORMATION

Community
  • 1
  • 1
bdoughan
  • 147,609
  • 23
  • 300
  • 400
2

I admit that Dozer is brilliant solution to this problem. I've tried it. And when you create a bean in spring like:

@Bean
  public Mapper getDozer(){
    return new DozerBeanMapper();
}

then you just inject mapper and wrap your object with:

private org.project.GetDocuments convertDocsInput(org.external.GetDocuments input) {
  return mapper.map(input, org.project.GetDocuments.class);
}
hanskoff
  • 182
  • 13
0

You can't cast them. You could use some reflective code to copy the values from one instance to another.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
0

A "crazy" idea can be to use GSon library. Convert the Object of type A into JSON then convert the JSON into an object of type B.

If A and B have fields with same name the value are set, otherwise skipped.

    A a = ....
    Gson gson = new Gson();
    String json = gson.toJson(a);
    B b = gson.fromJson(json, B.class);
Fedy2
  • 3,147
  • 4
  • 26
  • 44
0

I don't think java supports that kind of feature ,for casting two objects they must be in the same hierarchy.

in your scenario you can write some mapper that will map values from source to destination , but if you multiple classes like employer that contains same type of fields , you can go with two approaches that will end up in mapping code.

a) Use Dozer Mapping .

b) Or Generate a mapper at compile time ,that will do the mapping from source to destination and vice versa .

Note : I have used both the approaches for my project , only drawback with approach 1 is it is having some performance bottlenecks as it uses reflection for doing the mapping. On the other hand in approach (b) you have generated mappers after compilation and that is pure getter and setter based mapping. (No performance Bottleneck)

saurav
  • 3,424
  • 1
  • 22
  • 33
  • I've just looked at dozer and found how can I map POJO to JAXB, but how can I map JAXB to JAXB ? – user2508615 Jul 22 '13 at 18:01
  • upto my understanding there is nothing like POJO to JAXB or JAXB to JAXB .. everything in java is a POJO and Dozer supports POJO to POJO mapping without any hassle. Both of your Employers version are nothing but pojo only(only version of it might have jaxb annotation for schema generation)... so it will work in your case. – saurav Jul 22 '13 at 18:56
0

There is the Dozer project, which might help you (note: I haven't used it yet).

Puce
  • 37,247
  • 13
  • 80
  • 152
0

Using Apache commons-beanutils, you could do in 2 lines.

EmployerType targetType=com.beans.external.groupresponse.ObjectFactory.createEmployerType();
bodyResponse.setEmployer(
BeanUtils.copyProperties(targetType,sgCreateQuoteRequest.getRequest().getEmployer()));

I followed the example mentioned in java-object-copy-using-beanutils to address similar problem in my project.

sreddy
  • 49
  • 3