#1247 Make sure that nested target mappings works correctly for multiple source parameters

This commit is contained in:
Filip Hrisafov 2017-07-13 18:52:57 +02:00 committed by GitHub
parent d9821a0cc8
commit db3bb5eba0
11 changed files with 613 additions and 15 deletions

View File

@ -19,8 +19,9 @@
package org.mapstruct.ap.internal.model;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -56,7 +57,8 @@ public class NestedTargetPropertyMappingHolder {
Extractor<SourceReference, PropertyEntry>() {
@Override
public PropertyEntry apply(SourceReference sourceReference) {
return first( sourceReference.getPropertyEntries() );
return sourceReference.getPropertyEntries().isEmpty() ? null :
first( sourceReference.getPropertyEntries() );
}
};
@ -117,6 +119,8 @@ public class NestedTargetPropertyMappingHolder {
private Method method;
private MappingBuilderContext mappingContext;
private Set<String> existingVariableNames;
private List<PropertyMapping> propertyMappings;
private Set<String> handledTargets;
public Builder method(Method method) {
this.method = method;
@ -135,8 +139,8 @@ public class NestedTargetPropertyMappingHolder {
public NestedTargetPropertyMappingHolder build() {
List<Parameter> processedSourceParameters = new ArrayList<Parameter>();
Set<String> handledTargets = new HashSet<String>();
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
handledTargets = new HashSet<String>();
propertyMappings = new ArrayList<PropertyMapping>();
// first we group by the first property in the target properties and for each of those
// properties we get the new mappings as if the first property did not exist.
@ -164,7 +168,7 @@ public class NestedTargetPropertyMappingHolder {
// Lastly we need to group by the source references. This will allow us to actually create
// the next mappings by popping source elements
GroupedSourceReferences groupedSourceReferences = groupByPoppedSourceReferences(
entryByParam.getValue(),
entryByParam,
groupedByTP.singleTargetReferences.get( targetProperty )
);
@ -229,6 +233,13 @@ public class NestedTargetPropertyMappingHolder {
handledTargets.add( entryByTP.getKey().getName() );
}
handleSourceParameterMappings(
groupedSourceReferences.sourceParameterMappings,
targetProperty,
sourceParameter,
forceUpdateMethod
);
unprocessedDefinedTarget.put( targetProperty, groupedSourceReferences.notProcessedAppliesToAll );
}
}
@ -242,6 +253,43 @@ public class NestedTargetPropertyMappingHolder {
);
}
/**
* Handle the {@link PropertyMapping} creation for source parameter mappings.
*
* @param sourceParameterMappings the source parameter mappings for which property mapping should be done
* @param targetProperty the target property that is being mapped
* @param sourceParameter the source parameter that is used
* @param forceUpdateMethod whether we need to force an update method
*/
private void handleSourceParameterMappings(List<Mapping> sourceParameterMappings, PropertyEntry targetProperty,
Parameter sourceParameter, boolean forceUpdateMethod) {
if ( !sourceParameterMappings.isEmpty() ) {
// The source parameter mappings have no mappings, the source name is actually the parameter itself
MappingOptions nonNestedOptions = MappingOptions.forMappingsOnly(
new HashMap<String, List<Mapping>>(),
false,
true
);
SourceReference reference = new SourceReference.BuilderFromProperty()
.sourceParameter( sourceParameter )
.name( targetProperty.getName() )
.build();
PropertyMapping propertyMapping = createPropertyMappingForNestedTarget(
nonNestedOptions,
targetProperty,
reference,
forceUpdateMethod
);
if ( propertyMapping != null ) {
propertyMappings.add( propertyMapping );
}
handledTargets.add( targetProperty.getName() );
}
}
/**
* The target references are popped. The {@code List<}{@link Mapping}{@code >} are keyed on the unique first
* entries of the target references.
@ -464,15 +512,18 @@ public class NestedTargetPropertyMappingHolder {
*
*
*
* @param mappings the list of {@link Mapping} that needs to be used for grouping on popped source references
* @param entryByParam the entry of a {@link Parameter} and it's associated {@link Mapping}(s) that need to
* be used for grouping on popped source references
* @param singleTargetReferences the single target references that match the source mappings
*
* @return the Grouped Source References
*/
private GroupedSourceReferences groupByPoppedSourceReferences(List<Mapping> mappings,
private GroupedSourceReferences groupByPoppedSourceReferences(Map.Entry<Parameter, List<Mapping>> entryByParam,
List<Mapping> singleTargetReferences) {
List<Mapping> mappings = entryByParam.getValue();
List<Mapping> nonNested = new ArrayList<Mapping>();
List<Mapping> appliesToAll = new ArrayList<Mapping>();
List<Mapping> sourceParameterMappings = new ArrayList<Mapping>();
// group all mappings based on the top level name before popping
Map<PropertyEntry, List<Mapping>> mappingsKeyedByProperty
= new LinkedHashMap<PropertyEntry, List<Mapping>>();
@ -496,7 +547,24 @@ public class NestedTargetPropertyMappingHolder {
}
}
populateWithSingleTargetReferences( mappingsKeyedByProperty, singleTargetReferences, PROPERTY_EXTRACTOR );
// We consider that there were no mappings if there are no mappingsKeyedByProperty
// and no nonNested. appliesToAll Mappings are mappings that have no source reference and need to be
// applied to everything.
boolean hasNoMappings = mappingsKeyedByProperty.isEmpty() && nonNested.isEmpty();
Parameter sourceParameter = entryByParam.getKey();
List<Mapping> singleTargetReferencesToUse =
extractSingleTargetReferencesToUseAndPopulateSourceParameterMappings(
singleTargetReferences,
sourceParameterMappings,
hasNoMappings,
sourceParameter
);
populateWithSingleTargetReferences(
mappingsKeyedByProperty,
singleTargetReferencesToUse,
PROPERTY_EXTRACTOR
);
for ( Map.Entry<PropertyEntry, List<Mapping>> entry : mappingsKeyedByProperty.entrySet() ) {
entry.getValue().addAll( appliesToAll );
@ -516,10 +584,55 @@ public class NestedTargetPropertyMappingHolder {
return new GroupedSourceReferences(
mappingsKeyedByProperty,
nonNested,
notProcessedAppliesToAll
notProcessedAppliesToAll,
sourceParameterMappings
);
}
/**
* Extracts all relevant single target references and populates the {@code sourceParameterMappings} if needed.
* A relevant single target reference mapping is a mapping that has a valid source reference and is for
* the {@code sourceParameter}. If there are no mappings i.e. {@code hasNoMappings = true} and the source
* reference in the mapping has no property entries then add that to the {@code sourceParameterMappings}
* (mappings like this have found themselves here because there is a mapping method with multiple parameters
* and that are using the same sub-path in the target properties).
*
* @param singleTargetReferences All the single target references for a target property
* @param sourceParameterMappings a List that needs to be populated with valid mappings when {@code
* hasNoMappings = true} and there are no property entries in the source reference
* @param hasNoMappings parameter indicating whether there were any extracted mappings for this target property
* @param sourceParameter the source parameter for which the grouping is being done
*
* @return a list with valid single target references
*/
private List<Mapping> extractSingleTargetReferencesToUseAndPopulateSourceParameterMappings(
List<Mapping> singleTargetReferences, List<Mapping> sourceParameterMappings, boolean hasNoMappings,
Parameter sourceParameter) {
List<Mapping> singleTargetReferencesToUse = null;
if ( singleTargetReferences != null ) {
singleTargetReferencesToUse = new ArrayList<Mapping>( singleTargetReferences.size() );
for ( Mapping mapping : singleTargetReferences ) {
if ( mapping.getSourceReference() == null || !mapping.getSourceReference().isValid() ||
!sourceParameter.equals( mapping.getSourceReference().getParameter() ) ) {
// If the mapping has no sourceReference, it is not valid or it does not have the same source
// parameter then we need to ignore it. When a mapping method has multiple parameters it can
// happen that different parameters somehow have same path in the nesting
continue;
}
if ( hasNoMappings && mapping.getSourceReference().getPropertyEntries().isEmpty() ) {
// If there were no mappings for this source parameter and there are no property entries
// that means that this could be for a mapping method with multiple parameters.
// We have to consider and map this separately
sourceParameterMappings.add( mapping );
}
else {
singleTargetReferencesToUse.add( mapping );
}
}
}
return singleTargetReferencesToUse;
}
private Map<String, List<Mapping>> groupByTargetName(List<Mapping> mappingList) {
Map<String, List<Mapping>> result = new LinkedHashMap<String, List<Mapping>>();
for ( Mapping mapping : mappingList ) {
@ -563,11 +676,9 @@ public class NestedTargetPropertyMappingHolder {
//This are non nested target references only their property needs to be added as they most probably
// define it
for ( Mapping mapping : singleTargetReferences ) {
if ( mapping.getSourceReference() != null && mapping.getSourceReference().isValid()
&& !mapping.getSourceReference().getPropertyEntries().isEmpty() ) {
//TODO is this OK? Why there are no propertyEntries? For the Inverse LetterMapper for example
if ( mapping.getSourceReference() != null && mapping.getSourceReference().isValid() ) {
K key = keyExtractor.apply( mapping.getSourceReference() );
if ( !map.containsKey( key ) ) {
if ( key != null && !map.containsKey( key ) ) {
map.put( key, new ArrayList<Mapping>() );
}
}
@ -642,12 +753,15 @@ public class NestedTargetPropertyMappingHolder {
private final Map<PropertyEntry, List<Mapping>> groupedBySourceReferences;
private final List<Mapping> nonNested;
private final List<Mapping> notProcessedAppliesToAll;
private final List<Mapping> sourceParameterMappings;
private GroupedSourceReferences(Map<PropertyEntry, List<Mapping>> groupedBySourceReferences,
List<Mapping> nonNested, List<Mapping> notProcessedAppliesToAll) {
List<Mapping> nonNested, List<Mapping> notProcessedAppliesToAll,
List<Mapping> sourceParameterMappings) {
this.groupedBySourceReferences = groupedBySourceReferences;
this.nonNested = nonNested;
this.notProcessedAppliesToAll = notProcessedAppliesToAll;
this.sourceParameterMappings = sourceParameterMappings;
}
}

View File

@ -81,11 +81,25 @@ public class MappingOptions {
*/
public static MappingOptions forMappingsOnly(Map<String, List<Mapping>> mappings,
boolean restrictToDefinedMappings) {
return forMappingsOnly( mappings, restrictToDefinedMappings, restrictToDefinedMappings );
}
/**
* creates mapping options with only regular mappings
*
* @param mappings regular mappings to add
* @param restrictToDefinedMappings whether to restrict the mappings only to the defined mappings
* @param forForgedMethods whether the mappings are for forged methods
* @return MappingOptions with only regular mappings
*/
public static MappingOptions forMappingsOnly(Map<String, List<Mapping>> mappings,
boolean restrictToDefinedMappings, boolean forForgedMethods) {
return new MappingOptions(
mappings,
null,
null,
restrictToDefinedMappings ? BeanMapping.forForgedMethods() : null,
forForgedMethods ? BeanMapping.forForgedMethods() : null,
Collections.<ValueMapping>emptyList(),
restrictToDefinedMappings
);

View File

@ -0,0 +1,41 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
/**
* @author Filip Hrisafov
*/
public class DtoIn {
private final String data;
private final String data2;
public DtoIn(String data, String data2) {
this.data = data;
this.data2 = data2;
}
public String getData() {
return data;
}
public String getData2() {
return data2;
}
}

View File

@ -0,0 +1,44 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
/**
* @author Filip Hrisafov
*/
public class DtoOut {
private String data;
private InternalDto internal;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public InternalDto getInternal() {
return internal;
}
public void setInternal(InternalDto internal) {
this.internal = internal;
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
import java.util.List;
/**
* @author Filip Hrisafov
*/
public class InternalData {
private List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}

View File

@ -0,0 +1,44 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
/**
* @author Filip Hrisafov
*/
public class InternalDto {
private String data2;
private InternalData internalData;
public String getData2() {
return data2;
}
public void setData2(String data2) {
this.data2 = data2;
}
public InternalData getInternalData() {
return internalData;
}
public void setInternalData(InternalData internalData) {
this.internalData = internalData;
}
}

View File

@ -0,0 +1,51 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
import java.util.List;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper
public interface Issue1247Mapper {
Issue1247Mapper INSTANCE = Mappers.getMapper( Issue1247Mapper.class );
@Mappings( {
@Mapping(target = "internal", source = "in"),
@Mapping(target = "internal.internalData.list", source = "list")
} )
DtoOut map(DtoIn in, List<String> list);
@Mappings( {
@Mapping(target = "internal", source = "in"),
@Mapping(target = "internal.expression", expression = "java(\"testingExpression\")"),
@Mapping(target = "internal.internalData.list", source = "list"),
@Mapping(target = "internal.internalData.defaultValue", source = "in.data2", defaultValue = "missing"),
@Mapping(target = "constant", constant = "someConstant")
} )
OtherDtoOut mapWithConstantExpressionAndDefault(DtoIn in, List<String> list);
}

View File

@ -0,0 +1,101 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Filip Hrisafov
*/
@IssueKey("1247")
@RunWith(AnnotationProcessorTestRunner.class)
@WithClasses({
Issue1247Mapper.class,
DtoIn.class,
DtoOut.class,
InternalData.class,
InternalDto.class,
OtherDtoOut.class,
OtherInternalData.class,
OtherInternalDto.class
})
public class Issue1247Test {
@Test
public void shouldCorrectlyUseMappings() {
DtoIn in = new DtoIn( "data", "data2" );
List<String> list = Arrays.asList( "first", "second" );
DtoOut out = Issue1247Mapper.INSTANCE.map( in, list );
assertThat( out ).isNotNull();
assertThat( out.getData() ).isEqualTo( "data" );
assertThat( out.getInternal() ).isNotNull();
assertThat( out.getInternal().getData2() ).isEqualTo( "data2" );
assertThat( out.getInternal().getInternalData() ).isNotNull();
assertThat( out.getInternal().getInternalData().getList() ).containsExactly( "first", "second" );
}
@Test
public void shouldCorrectlyUseMappingsWithConstantsExpressionsAndDefaults() {
DtoIn in = new DtoIn( "data", "data2" );
List<String> list = Arrays.asList( "first", "second" );
OtherDtoOut out = Issue1247Mapper.INSTANCE.mapWithConstantExpressionAndDefault( in, list );
assertThat( out ).isNotNull();
assertThat( out.getData() ).isEqualTo( "data" );
assertThat( out.getConstant() ).isEqualTo( "someConstant" );
assertThat( out.getInternal() ).isNotNull();
// This will not be mapped by the @Mapping(target = "internal", source = "in") because we have one more
// symmetric mapping @Mapping(target = "internal.expression", expression = "java(\"testingExpression\")")
assertThat( out.getInternal().getData2() ).isNull();
assertThat( out.getInternal().getExpression() ).isEqualTo( "testingExpression" );
assertThat( out.getInternal().getInternalData() ).isNotNull();
assertThat( out.getInternal().getInternalData().getList() ).containsExactly( "first", "second" );
assertThat( out.getInternal().getInternalData().getDefaultValue() ).isEqualTo( "data2" );
}
@Test
public void shouldCorrectlyUseMappingsWithConstantsExpressionsAndUseDefault() {
DtoIn in = new DtoIn( "data", null );
List<String> list = Arrays.asList( "first", "second" );
OtherDtoOut out = Issue1247Mapper.INSTANCE.mapWithConstantExpressionAndDefault( in, list );
assertThat( out ).isNotNull();
assertThat( out.getData() ).isEqualTo( "data" );
assertThat( out.getConstant() ).isEqualTo( "someConstant" );
assertThat( out.getInternal() ).isNotNull();
assertThat( out.getInternal().getData2() ).isNull();
assertThat( out.getInternal().getExpression() ).isEqualTo( "testingExpression" );
assertThat( out.getInternal().getInternalData() ).isNotNull();
assertThat( out.getInternal().getInternalData().getList() ).containsExactly( "first", "second" );
assertThat( out.getInternal().getInternalData().getDefaultValue() ).isEqualTo( "missing" );
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
/**
* @author Filip Hrisafov
*/
public class OtherDtoOut {
private String data;
private OtherInternalDto internal;
private String constant;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public OtherInternalDto getInternal() {
return internal;
}
public void setInternal(OtherInternalDto internal) {
this.internal = internal;
}
public String getConstant() {
return constant;
}
public void setConstant(String constant) {
this.constant = constant;
}
}

View File

@ -0,0 +1,46 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
import java.util.List;
/**
* @author Filip Hrisafov
*/
public class OtherInternalData {
private List<String> list;
private String defaultValue;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
* and/or other contributors as indicated by the @authors tag. See the
* copyright.txt file in the distribution for a full listing of all
* contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mapstruct.ap.test.bugs._1247;
/**
* @author Filip Hrisafov
*/
public class OtherInternalDto {
private String data2;
private String expression;
private OtherInternalData internalData;
public String getData2() {
return data2;
}
public void setData2(String data2) {
this.data2 = data2;
}
public String getExpression() {
return expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
public OtherInternalData getInternalData() {
return internalData;
}
public void setInternalData(OtherInternalData internalData) {
this.internalData = internalData;
}
}