jaxb生成的非公共列表字段和modelmapper缺少的setter的javaMap对象

hof1towb  于 2021-07-08  发布在  Java
关注(0)|答案(2)|浏览(326)

我有jaxb生成的数据结构。部分结构基本上是相同的,但它们位于不同的名称空间中,因此生成的java类型是不同的。
我需要在这些结构之间传输数据。在项目中,modelmapper用于Map,因此我希望使用它。
我的问题是modelmapper无法Map为“maxoccurs=”unbounded“”元素生成的列表。
假设我有以下模式:

<xs:complexType name="CityData">
    <xs:sequence>
        <xs:element name="districtData" type="DistrictData" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="DistrictData">
    <xs:sequence>
        <xs:element name="population" type="xs:int" nillable="false" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
</xs:complexType>

我在namespacea和namespaceb中都有这个模式,因此jaxb在package namespacea和package namespaceb中生成以下类型:

public class CityData {
    @XmlElement(required = true)
    protected List<DistrictData> districtData;
    //... jaxb explanation why there's no setter
    public List<DistrictData> getDistrictData() {
        if (districtData == null) {
            districtData = new ArrayList<DistrictData>();
        }
        return this.districtData;
    }
}

public class DistrictData {
    protected int population;
    public int getPopulation() {
        return population;
    }
    public void setPopulation(int value) {
        this.population = value;
    }
}

现在,如果我从包namespacea创建一个源citydata,并要求modelmapper将其Map到namespaceb中的目标citydata,那么数据不会被Map:

CityData cityData = new CityData();
    DistrictData districtData = new DistrictData();
    districtData.setPopulation(1234);
    cityData.getDistrictData().add(districtData);

    ModelMapper modelMapper = new ModelMapper();
    modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

    namespaceb.CityData dest = modelMapper.map(cityData, namespaceb.CityData.class);
    System.out.println("dest.districtData: " + dest.getDistrictData());

结果是:

dest.districtData: []

换句话说,districtdata不会复制到目标。
我知道modelmapper没有为districtdata找到setter,因此没有Map它。我了解到可以重新配置jaxb来为列表属性生成setter,但是jaxb对象生成并不在我的项目中。
因此,我想知道是否有一个很好的解决方案,用于使用modelmapper进行Map,或者在这些情况下使用其他mapper库进行Map。
我创建了一个小项目:https://github.com/riskop/modelmapperjaxb

nimxete2

nimxete21#

我认为您只需要启用fieldmatching并设置要匹配的字段的访问级别来处理缺少的setter。检查此配置:

modelMapper.getConfiguration()
    .setMatchingStrategy(MatchingStrategies.STRICT)
    .setFieldMatchingEnabled(true)
    .setFieldAccessLevel(AccessLevel.PROTECTED);

javadoc公司:
已启用setfieldaccessenabled
设置是否应启用字段匹配。如果为true,则可以在可访问字段之间进行Map。默认值为false。
设置字段访问级别
指示字段应符合给定访问级别的匹配条件。
注意:字段访问仅在启用字段匹配时使用。

1u4esq0p

1u4esq0p2#

在阅读pirho的答案之前,我对modelmapper.converter工具的笨拙解决方法有了一个粗略的了解。我认为皮罗的答案更好(被接受),但作为记录,下面是转换器的解决方法。这基本上是为没有设置器的子结构手动定义转换:

CountryData countryData = new CountryData();
CityData cityData = new CityData();
DistrictData districtData = new DistrictData();
districtData.setPopulation(1234);
cityData.getDistrictData().add(districtData);
countryData.getCityData().add(cityData);

ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

modelMapper.addConverter(new Converter<CountryData, namespaceb.CountryData>() {
    @Override
    public namespaceb.CountryData convert(MappingContext<CountryData, namespaceb.CountryData> context) {
        namespaceb.CountryData result = new namespaceb.CountryData();
        if(context.getSource() != null) {
            for(CityData cityData : context.getSource().getCityData()) {
                namespaceb.CityData mapped = modelMapper.map(cityData, namespaceb.CityData.class);
                result.getCityData().add(mapped);
            }
        }
        return result;
    }
});

modelMapper.addConverter(new Converter<CityData, namespaceb.CityData>() {
    @Override
    public namespaceb.CityData convert(MappingContext<CityData, namespaceb.CityData> context) {
        namespaceb.CityData result = new namespaceb.CityData();
        if(context.getSource() != null) {
            for(DistrictData districtData : context.getSource().getDistrictData()) {
                namespaceb.DistrictData mapped = modelMapper.map(districtData, namespaceb.DistrictData.class);
                result.getDistrictData().add(mapped);
            }
        }
        return result;
    }
});

namespaceb.CountryData destCountryData = modelMapper.map(countryData, namespaceb.CountryData.class);
assertEquals(1, destCountryData.getCityData().size());
namespaceb.CityData destCityData = destCountryData.getCityData().get(0);
assertEquals(1, destCityData.getDistrictData().size());
namespaceb.DistrictData destDistrictData = destCityData.getDistrictData().get(0);
assertEquals(1234, destDistrictData.getPopulation());

相关问题