From 8a28f129995bc417cbc7ec991f28f8b783f6b55b Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Wed, 3 Feb 2016 23:19:25 +0100 Subject: [PATCH] #634 Using DeclaredType instead of TypeElement when resolving property accessors of mapped bean types; That way accessor parameter/return types referring to type parameters of the bean will be resolved correctly --- .../ap/internal/model/BeanMappingMethod.java | 5 +- .../ap/internal/model/PropertyMapping.java | 8 ++- .../ap/internal/model/common/Type.java | 7 ++- .../ap/internal/model/common/TypeFactory.java | 15 ++--- .../model/source/SourceReference.java | 5 +- .../processor/MethodRetrievalProcessor.java | 20 +++---- .../ap/internal/util/MapperConfiguration.java | 37 +++++++++---- .../ap/test/generics/container/Bar.java | 39 +++++++++++++ .../ap/test/generics/container/Foo.java | 36 ++++++++++++ .../container/GenericContainerTest.java | 55 +++++++++++++++++++ .../ap/test/generics/container/Source.java | 34 ++++++++++++ .../container/SourceTargetMapper.java | 32 +++++++++++ .../ap/test/generics/container/Target.java | 34 ++++++++++++ 13 files changed, 287 insertions(+), 40 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/generics/container/Bar.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/generics/container/Foo.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/generics/container/GenericContainerTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/generics/container/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/generics/container/SourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/generics/container/Target.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index 135960425..c9d4fcf3e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -33,7 +33,7 @@ import java.util.Map.Entry; import java.util.Set; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; @@ -407,8 +407,7 @@ public class BeanMappingMethod extends MappingMethod { ExecutableElement sourceAccessor = getSourceAccessor( targetProperty.getKey(), candidates ); if ( sourceAccessor != null ) { Mapping mapping = method.getSingleMappingByTargetPropertyName( targetProperty.getKey() ); - - TypeElement sourceType = sourceParameter.getType().getTypeElement(); + DeclaredType sourceType = (DeclaredType) sourceParameter.getType().getTypeMirror(); SourceReference sourceRef = new SourceReference.BuilderFromProperty() .sourceParameter( sourceParameter ) diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java index f4e647372..b6468b5ab 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Set; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import org.mapstruct.ap.internal.model.assignment.AdderWrapper; @@ -130,16 +131,19 @@ public class PropertyMapping extends ModelElement { } private Type determineTargetType() { + // This is a bean mapping method, so we know the result is a declared type + DeclaredType resultType = (DeclaredType) method.getResultType().getTypeMirror(); + switch ( targetWriteAccessorType ) { case ADDER: case SETTER: return ctx.getTypeFactory() - .getSingleParameter( method.getResultType().getTypeElement(), targetWriteAccessor ) + .getSingleParameter( resultType, targetWriteAccessor ) .getType(); case GETTER: default: return ctx.getTypeFactory() - .getReturnType( method.getResultType().getTypeElement(), targetWriteAccessor ); + .getReturnType( resultType, targetWriteAccessor ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java index 2129f2ee1..4f0d98db6 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java @@ -35,6 +35,7 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.WildcardType; @@ -396,7 +397,7 @@ public class Type extends ModelElement implements Comparable { // first check if there's a setter method. ExecutableElement adderMethod = null; if ( Executables.isSetterMethod( candidate ) ) { - Type targetType = typeFactory.getSingleParameter( typeElement, candidate ).getType(); + Type targetType = typeFactory.getSingleParameter( (DeclaredType) typeMirror, candidate ).getType(); // ok, the current accessor is a setter. So now the strategy determines what to use if ( cmStrategy == CollectionMappingStrategyPrism.ADDER_PREFERRED ) { adderMethod = getAdderForType( targetType, targetPropertyName ); @@ -405,7 +406,9 @@ public class Type extends ModelElement implements Comparable { else if ( Executables.isGetterMethod( candidate ) ) { // the current accessor is a getter (no setter available). But still, an add method is according // to the above strategy (SETTER_PREFERRED || ADDER_PREFERRED) preferred over the getter. - Type targetType = typeFactory.getReturnType( typeFactory.getMethodType( typeElement, candidate ) ); + Type targetType = typeFactory.getReturnType( + typeFactory.getMethodType( (DeclaredType) typeMirror, candidate ) + ); adderMethod = getAdderForType( targetType, targetPropertyName ); } if ( adderMethod != null ) { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java index 672e6de6d..17cd2ccff 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java @@ -18,8 +18,6 @@ */ package org.mapstruct.ap.internal.model.common; -import static org.mapstruct.ap.internal.util.workarounds.SpecificCompilerWorkarounds.replaceTypeElementIfNecessary; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -256,13 +254,12 @@ public class TypeFactory { * @param method the method * @return the ExecutableType representing the method as part of usedMapper */ - public ExecutableType getMethodType(TypeElement includingType, ExecutableElement method) { - DeclaredType asType = (DeclaredType) replaceTypeElementIfNecessary( elementUtils, includingType ).asType(); - TypeMirror asMemberOf = typeUtils.asMemberOf( asType, method ); + public ExecutableType getMethodType(DeclaredType includingType, ExecutableElement method) { + TypeMirror asMemberOf = typeUtils.asMemberOf( includingType, method ); return (ExecutableType) asMemberOf; } - public Parameter getSingleParameter(TypeElement includingType, ExecutableElement method) { + public Parameter getSingleParameter(DeclaredType includingType, ExecutableElement method) { List parameters = method.getParameters(); if ( parameters.size() != 1 ) { @@ -273,7 +270,7 @@ public class TypeFactory { return Collections.first( getParameters( includingType, method ) ); } - public List getParameters(TypeElement includingType, ExecutableElement method) { + public List getParameters(DeclaredType includingType, ExecutableElement method) { return getParameters( getMethodType( includingType, method ), method ); } @@ -299,7 +296,7 @@ public class TypeFactory { return result; } - public Type getReturnType(TypeElement includingType, ExecutableElement method) { + public Type getReturnType(DeclaredType includingType, ExecutableElement method) { return getReturnType( getMethodType( includingType, method ) ); } @@ -307,7 +304,7 @@ public class TypeFactory { return getType( method.getReturnType() ); } - public List getThrownTypes(TypeElement includingType, ExecutableElement method) { + public List getThrownTypes(DeclaredType includingType, ExecutableElement method) { return getThrownTypes( getMethodType( includingType, method ) ); } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java index 95c1c7acd..364ee1b7a 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.DeclaredType; import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Type; @@ -176,7 +177,9 @@ public class SourceReference { Map sourceReadAccessors = newType.getPropertyReadAccessors(); for ( Map.Entry getter : sourceReadAccessors.entrySet() ) { if ( getter.getKey().equals( entryName ) ) { - newType = typeFactory.getReturnType( newType.getTypeElement(), getter.getValue() ); + newType = typeFactory.getReturnType( + (DeclaredType) newType.getTypeMirror(), getter.getValue() + ); sourceEntries.add( new PropertyEntry( entryName, getter.getValue(), newType ) ); matchFound = true; break; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java index 5adc5f435..251f592fb 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java @@ -32,7 +32,6 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; @@ -86,8 +85,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor prototypeMethods = - retrievePrototypeMethods( mapperConfig.getMapperConfigMirror(), mapperConfig ); + List prototypeMethods = retrievePrototypeMethods( mapperConfig ); return retrieveMethods( mapperTypeElement, mapperTypeElement, mapperConfig, prototypeMethods ); } @@ -96,16 +94,16 @@ public class MethodRetrievalProcessor implements ModelElementProcessor retrievePrototypeMethods(TypeMirror typeMirror, MapperConfiguration mapperConfig ) { - if ( typeMirror == null || typeMirror.getKind() == TypeKind.VOID ) { + private List retrievePrototypeMethods(MapperConfiguration mapperConfig ) { + if ( mapperConfig.config() == null ) { return Collections.emptyList(); } - TypeElement typeElement = asTypeElement( typeMirror ); + TypeElement typeElement = asTypeElement( mapperConfig.config() ); List methods = new ArrayList(); for ( ExecutableElement executable : getAllEnclosedExecutableElements( elementUtils, typeElement ) ) { - ExecutableType methodType = typeFactory.getMethodType( typeElement, executable ); + ExecutableType methodType = typeFactory.getMethodType( mapperConfig.config(), executable ); List parameters = typeFactory.getParameters( methodType, executable ); boolean containsTargetTypeParameter = SourceMethod.containsTargetTypeParameter( parameters ); @@ -158,7 +156,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor prototypeMethods) { - ExecutableType methodType = typeFactory.getMethodType( usedMapper, method ); + ExecutableType methodType = typeFactory.getMethodType( (DeclaredType) usedMapper.asType(), method ); List parameters = typeFactory.getParameters( methodType, method ); Type returnType = typeFactory.getReturnType( methodType ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java b/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java index 2a171a220..50b7c6b05 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/MapperConfiguration.java @@ -18,7 +18,6 @@ */ package org.mapstruct.ap.internal.util; -import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -26,7 +25,6 @@ import java.util.Set; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism; @@ -49,6 +47,7 @@ public class MapperConfiguration { private final MapperPrism mapperPrism; private final MapperConfigPrism mapperConfigPrism; + private final DeclaredType config; public static MapperConfiguration getInstanceOn(Element e) { return new MapperConfiguration( MapperPrism.getInstanceOn( e ) ); @@ -56,11 +55,15 @@ public class MapperConfiguration { private MapperConfiguration(MapperPrism mapperPrism) { this.mapperPrism = mapperPrism; - TypeMirror typeMirror = mapperPrism.config(); - if ( typeMirror.getKind().equals( TypeKind.DECLARED ) ) { - this.mapperConfigPrism = MapperConfigPrism.getInstanceOn( ( (DeclaredType) typeMirror ).asElement() ); + + if ( mapperPrism.values.config() != null ) { + // TODO #737 Only a declared type makes sense here; Validate and raise graceful error; + // Also validate that @MapperConfig is present + this.config = (DeclaredType) mapperPrism.config(); + this.mapperConfigPrism = MapperConfigPrism.getInstanceOn( config.asElement() ); } else { + this.config = null; this.mapperConfigPrism = null; } } @@ -83,12 +86,22 @@ public class MapperConfiguration { } } - public List uses() { - Set uses = new LinkedHashSet( mapperPrism.uses() ); - if ( mapperConfigPrism != null ) { - uses.addAll( mapperConfigPrism.uses() ); + public Set uses() { + Set uses = new LinkedHashSet(); + + for ( TypeMirror usedMapperType : mapperPrism.uses() ) { + // TODO #737 Only declared type make sense here; Validate and raise graceful error; + uses.add( (DeclaredType) usedMapperType ); } - return new ArrayList( uses ); + + if ( mapperConfigPrism != null ) { + for ( TypeMirror usedMapperType : mapperConfigPrism.uses() ) { + // TODO #737 Only declared type make sense here; Validate and raise graceful error; + uses.add( (DeclaredType) usedMapperType ); + } + } + + return uses; } public List imports() { @@ -155,8 +168,8 @@ public class MapperConfiguration { } } - public TypeMirror getMapperConfigMirror() { - return mapperPrism.config(); + public DeclaredType config() { + return config; } public boolean isValid() { diff --git a/processor/src/test/java/org/mapstruct/ap/test/generics/container/Bar.java b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Bar.java new file mode 100644 index 000000000..cf0272936 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Bar.java @@ -0,0 +1,39 @@ +/** + * Copyright 2012-2016 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.generics.container; + +public class Bar { + + private long value; + + public Bar() { + } + + public Bar(long value) { + this.value = value; + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/generics/container/Foo.java b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Foo.java new file mode 100644 index 000000000..f7adadb83 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Foo.java @@ -0,0 +1,36 @@ +/** + * Copyright 2012-2016 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.generics.container; + +public class Foo { + + private String value; + + public Foo(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/generics/container/GenericContainerTest.java b/processor/src/test/java/org/mapstruct/ap/test/generics/container/GenericContainerTest.java new file mode 100644 index 000000000..1727fb0e8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/generics/container/GenericContainerTest.java @@ -0,0 +1,55 @@ +/** + * Copyright 2012-2016 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.generics.container; + +import static org.fest.assertions.Assertions.assertThat; + +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; + +/** + * @author Gunnar Morling + */ +@WithClasses({ + Bar.class, + Foo.class, + Source.class, + Target.class, + SourceTargetMapper.class, +}) +@RunWith(AnnotationProcessorTestRunner.class) +public class GenericContainerTest { + + @Test + @IssueKey("634") + public void canMapGenericSourceTypeToGenericTargetType() { + List items = Arrays.asList( new Foo( "42" ), new Foo( "84" ) ); + Source source = new Source( items ); + + Target target = SourceTargetMapper.INSTANCE.mapSourceToTarget( source ); + + assertThat( target.getContent() ).onProperty( "value" ).containsExactly( 42L, 84L ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/generics/container/Source.java b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Source.java new file mode 100644 index 000000000..858f62cad --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Source.java @@ -0,0 +1,34 @@ +/** + * Copyright 2012-2016 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.generics.container; + +import java.util.List; + +public class Source { + + private final List items; + + public Source(List items) { + this.items = items; + } + + public List getContent() { + return items; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/generics/container/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/generics/container/SourceTargetMapper.java new file mode 100644 index 000000000..ee2b353c7 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/generics/container/SourceTargetMapper.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2016 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.generics.container; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface SourceTargetMapper { + + SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + Bar mapFooToBar(Foo foo); + + Target mapSourceToTarget(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/generics/container/Target.java b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Target.java new file mode 100644 index 000000000..06e290b9d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/generics/container/Target.java @@ -0,0 +1,34 @@ +/** + * Copyright 2012-2016 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.generics.container; + +import java.util.List; + +public class Target { + + private List content; + + public List getContent() { + return content; + } + + public void setContent(List content) { + this.content = content; + } +}