简体   繁体   中英

How do I map an object contained in a collection to a field and viceversa? Dozer

I'm struggling from two days now with this trouble and I can't get it. I have:

public class ClientBo{
  ...
  List<PersonBo> person;
  ...
}

and

public class ClientVo{
   ...
   PersonVo person;
   ...
}

What I need to do is to configure somehow dozer, so i can map from List of PersonBo to single field PersonVo(Vo an Bo have same field names).

Dozer has a build in function that converts from collection to single field, but not the other way. http://dozer.sourceforge.net/documentation/faq.html#mult-fields-to-single-field

The only solution that i figured out is :

<mapping type="one-way">
    <class-a>...ClientBo</class-a>
    <class-b>...ClientVo</class-b>
    <field>
        <a>person[0]</a>
        <b>person</b>
    </field>
</mapping>
<mapping type="one-way">
    <class-a>...ClientVo</class-a>
    <class-b>...ClientBo</class-b>
    <field custom-converter="mapper.CustomObjectToList">
        <a>person</a>
        <b>person</b>
    </field>
</mapping>

and

   public class CustomObjectToList implements CustomConverter{

        public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
            if(sourceFieldValue==null)
                return null;

            if(sourceFieldValue instanceof List && ((List<?>) sourceFieldValue).size()>0){
               /* This if is an attempt to get the first element of the
                list and return it as a single field, but id doesn't work*/
                Object o = ((List<?>)sourceFieldValue).get(0);
                return o;


            }else{
                /*Here a single field is put in a List and returned*/
                ArrayList<Object> result = new ArrayList<>();
                result.add(sourceFieldValue);
                return result;
            }
        }
    }

Is there any way so I can remove

   <mapping type="one-way">
       <class-a>...ClientBo</class-a>
       <class-b>...ClientVo</class-b>
       <field>
            <a>person[0]</a>
            <b>person</b>
       </field>
   </mapping>

and get the job done by a custom converter? It should be more generic as possible, so it can fit in similar contexts.

Thanks!

1. Did you try testing your CustomConverter?

Because if you tried printing out any of the variables you would have got a ClassCastException , like this:

Exception in thread "main" java.lang.ClassCastException: beans.PersonVo cannot be cast to beans.PersonBo
    at execute.Execute.main(Execute.java:37)

Yes, fields with the same names do get mapped automatically, but in your case you are using a CustomConverter to do the mapping. In other words, Dozer is trusting you to take care of it, so you cannot simply point one Class variable (personVo) to another unrelated Class instance (personBo).

2. Correcting the above Exception

The easiest way to correct the above exception is to to use the setter and getter methods, like you would for any unrelated classes:

public class CustomObjectToList implements CustomConverter{

public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
    if(sourceFieldValue==null)
        return null;

    if(sourceFieldValue instanceof List && ((List<?>) sourceFieldValue).size()>0){
       /* This if is an attempt to get the first element of the
        list and return it as a single field, but id doesn't work*/
        Object o = ((List<?>)sourceFieldValue).get(0);
        return o;


    }else{
        /*Updated: using a setter and getter*/
        PersonVo source = (PersonVo) sourceFieldValue;
        List<PersonBo> dest  = new ArrayList<PersonBo>();

        PersonBo bo = new PersonBo();
        bo.setName(source.getName());
        dest.add(bo);
        return dest;
    }
}
}

3. Answer to your question

To do away with one-way mapping and use only a CustomConverter, you could use the following:

dozer XML:

<!-- <mapping type="one-way">
    <class-a>beans.ClientBo</class-a>
    <class-b>beans.ClientVo</class-b>
    <field>
        <a>person[0]</a>
        <b>person</b>
    </field>
</mapping> -->
<mapping>
    <class-a>beans.ClientVo</class-a>
    <class-b>beans.ClientBo</class-b>
    <field custom-converter="converter.CustomObjectToList">
        <a>person</a>
        <b>person</b>
    </field>
</mapping>

CustomConverter:

public class CustomObjectToList implements CustomConverter{

public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
        if(sourceFieldValue==null)
            return null;

        if(sourceFieldValue instanceof PersonVo){
            PersonVo source = (PersonVo) sourceFieldValue;
            List<PersonBo> dest  = new ArrayList<PersonBo>();

            PersonBo bo = new PersonBo();
            bo.setName(source.getName());
            dest.add(bo);
            return dest;

        }else if (sourceFieldValue instanceof List<?>){
            List<PersonBo> source = (List<PersonBo>) sourceFieldValue;

            PersonVo dest = new PersonVo();
            dest.setName(source.get(0).getName());
            return dest;
        }
        else {
            throw new MappingException("Converter TestCustomConverter "
                + "used incorrectly. Arguments passed in were:"
                + existingDestinationFieldValue + " and " + sourceFieldValue);
          }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM