From dd7f296e2b0a63b710b7bf60120e1823551af4be Mon Sep 17 00:00:00 2001 From: "Textor Andreas (BCI/ESW17)" Date: Fri, 3 Nov 2023 10:58:28 +0100 Subject: [PATCH] Fix static Java code generation to work with custom quantity kinds --- .../java/ValueExpressionVisitor.java | 10 +- .../aspectmodel/java/ValueInitializer.java | 38 +++--- .../metamodel/StaticMetaModelVisitor.java | 114 +++++++++++------- 3 files changed, 99 insertions(+), 63 deletions(-) diff --git a/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueExpressionVisitor.java b/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueExpressionVisitor.java index 642e8f5aa..ba31f1f2f 100644 --- a/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueExpressionVisitor.java +++ b/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueExpressionVisitor.java @@ -19,6 +19,7 @@ import org.apache.jena.rdf.model.Resource; import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.vocabulary.RDF; + import org.eclipse.esmf.aspectmodel.java.exception.CodeGenerationException; import org.eclipse.esmf.aspectmodel.resolver.services.DataType; import org.eclipse.esmf.metamodel.CollectionValue; @@ -37,7 +38,8 @@ *
  • If the value is (int) 3, it will return "3"
  • *
  • If the value is (String) "hi", it will return "\"hi\""
  • *
  • If the value is (LangString) "hi"@en, it will return "new LangString(\"hi\", Locale.forLanguageTag(\"en\"))"
  • - *
  • If the value is a collection, it will return the corresponding collection, e.g. "new ArrayList<>(){{ add(1); add(2); add(3); }}"
  • + *
  • If the value is a collection, it will return the corresponding collection, e.g. "new ArrayList<>(){{ add(1); add(2); add(3); }} + * "
  • *
  • If the value is an Entity, it will return the corresponding constructor call, e.g. "new MyEntity(\"foo\", 2, 3)"
  • * */ @@ -70,7 +72,8 @@ private String generateValueExpression( final ScalarValue value, final Context c context.getCodeGenerationConfig().importTracker().importExplicit( LangString.class ); context.getCodeGenerationConfig().importTracker().importExplicit( Locale.class ); final LangString langStringValue = (LangString) value.as( ScalarValue.class ).getValue(); - return String.format( "new LangString(\"%s\", Locale.forLanguageTag(\"%s\"))", AspectModelJavaUtil.escapeForLiteral( langStringValue.getValue() ), + return String.format( "new LangString(\"%s\", Locale.forLanguageTag(\"%s\"))", + AspectModelJavaUtil.escapeForLiteral( langStringValue.getValue() ), langStringValue.getLanguageTag().toLanguageTag() ); } @@ -107,7 +110,8 @@ public String visitEntityInstance( final EntityInstance instance, final Context if ( property.isOptional() ) { return "null"; } - throw new CodeGenerationException( "EntityInstance " + instance.getName() + " is missing value for Property " + property.getName() ); + throw new CodeGenerationException( + "EntityInstance " + instance.getName() + " is missing value for Property " + property.getName() ); } final Context newContext = new Context( context.codeGenerationConfig, property.isOptional() ); return value.accept( this, newContext ); diff --git a/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueInitializer.java b/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueInitializer.java index b80d2691a..6539181b0 100644 --- a/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueInitializer.java +++ b/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/ValueInitializer.java @@ -37,17 +37,18 @@ public class ValueInitializer { static { final BiFunction, String, String> literalExpression = ( type, valueExpression ) -> valueExpression; - final BiFunction, String, String> stringConstructor = ( type, valueExpression ) -> String.format( "new %s( %s )", type.getSimpleName(), - valueExpression ); - final BiFunction, String, String> create = ( type, valueExpression ) -> String.format( "%s.create( %s )", type.getSimpleName(), - valueExpression ); - final BiFunction, String, String> parseTypeName = ( type, valueExpression ) -> String.format( "%s.parse%s( %s )", type.getSimpleName(), + final BiFunction, String, String> stringConstructor = ( type, valueExpression ) -> String.format( "new %s( %s )", type.getSimpleName(), valueExpression ); - final BiFunction, String, String> valueOf = ( type, valueExpression ) -> String.format( "%s.valueOf( %s )", type.getSimpleName(), - valueExpression ); - final BiFunction, String, String> gregorianCalendar = ( type, valueExpression ) -> "_datatypeFactory.newXMLGregorianCalendar( " + valueExpression + final BiFunction, String, String> create = ( type, valueExpression ) -> String.format( "%s.create( %s )", + type.getSimpleName(), valueExpression ); + final BiFunction, String, String> parseTypeName = ( type, valueExpression ) -> String.format( "%s.parse%s( %s )", + type.getSimpleName(), type.getSimpleName(), valueExpression ); + final BiFunction, String, String> valueOf = ( type, valueExpression ) -> String.format( "%s.valueOf( %s )", + type.getSimpleName(), valueExpression ); + final BiFunction, String, String> gregorianCalendar = ( type, valueExpression ) -> + "_datatypeFactory.newXMLGregorianCalendar( " + valueExpression + " )"; + final BiFunction, String, String> duration = ( type, valueExpression ) -> "_datatypeFactory.newDuration( " + valueExpression + " )"; - final BiFunction, String, String> duration = ( type, valueExpression ) -> "_datatypeFactory.newDuration( " + valueExpression + " )"; INITIALIZERS = new HashMap<>(); INITIALIZERS.put( XSD.xstring, literalExpression ); @@ -59,11 +60,13 @@ public class ValueInitializer { INITIALIZERS.put( XSD.date, gregorianCalendar ); INITIALIZERS.put( XSD.dateTime, gregorianCalendar ); INITIALIZERS.put( XSD.dateTimeStamp, gregorianCalendar ); - INITIALIZERS.put( XSD.gYear, ( type, valueExpression ) -> "_datatypeFactory.newXMLGregorianCalendarDate( Integer.valueOf( " + valueExpression + " )" - + ", DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED )" ); + INITIALIZERS.put( XSD.gYear, + ( type, valueExpression ) -> "_datatypeFactory.newXMLGregorianCalendarDate( Integer.valueOf( " + valueExpression + " )" + + ", DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED )" ); INITIALIZERS.put( XSD.gMonth, - ( type, valueExpression ) -> "_datatypeFactory.newXMLGregorianCalendarDate( DatatypeConstants.FIELD_UNDEFINED, Integer.valueOf( " + valueExpression - + " )" + ", DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED )" ); + ( type, valueExpression ) -> + "_datatypeFactory.newXMLGregorianCalendarDate( DatatypeConstants.FIELD_UNDEFINED, Integer.valueOf( " + valueExpression + + " )" + ", DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED )" ); INITIALIZERS.put( XSD.gYearMonth, gregorianCalendar ); INITIALIZERS.put( XSD.gMonthDay, gregorianCalendar ); INITIALIZERS.put( XSD.gDay, gregorianCalendar ); @@ -88,8 +91,10 @@ public class ValueInitializer { } public boolean needInitializationToConstructor( final List deconstructionSets ) { - return deconstructionSets.stream().flatMap( deconstructionSet -> deconstructionSet.getElementProperties().stream().map( property -> property.getDataType() - .map( type -> DataType.getJavaTypeForMetaModelType( ResourceFactory.createResource( type.getUrn() ), property.getMetaModelVersion() ) ) ) ) + return deconstructionSets.stream() + .flatMap( deconstructionSet -> deconstructionSet.getElementProperties().stream().map( property -> property.getDataType() + .map( type -> DataType.getJavaTypeForMetaModelType( ResourceFactory.createResource( type.getUrn() ), + property.getMetaModelVersion() ) ) ) ) .anyMatch( dataType -> dataType.map( type -> type == XMLGregorianCalendar.class ).orElse( false ) ); } @@ -114,7 +119,8 @@ public String apply( final Resource rdfType, final String valueExpression, final * @param valueExpression an expression that, when evaluated, will return the input value as a string. * @param metaModelVersion the used meta model version */ - public String apply( final Resource rdfType, final Class javaType, final String valueExpression, final KnownVersion metaModelVersion ) { + public String apply( final Resource rdfType, final Class javaType, final String valueExpression, + final KnownVersion metaModelVersion ) { final SAMM samm = new SAMM( metaModelVersion ); if ( rdfType.equals( samm.curie() ) ) { return String.format( "new Curie( %s )", valueExpression ); diff --git a/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/metamodel/StaticMetaModelVisitor.java b/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/metamodel/StaticMetaModelVisitor.java index d3410a182..3390003eb 100644 --- a/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/metamodel/StaticMetaModelVisitor.java +++ b/core/esmf-aspect-model-java-generator/src/main/java/org/eclipse/esmf/aspectmodel/java/metamodel/StaticMetaModelVisitor.java @@ -23,10 +23,6 @@ import java.util.function.Supplier; import java.util.stream.Collectors; -import org.apache.commons.text.StringEscapeUtils; -import org.apache.jena.rdf.model.Resource; -import org.apache.jena.rdf.model.ResourceFactory; -import org.apache.jena.vocabulary.XSD; import org.eclipse.esmf.aspectmodel.java.AspectModelJavaUtil; import org.eclipse.esmf.aspectmodel.java.ValueExpressionVisitor; import org.eclipse.esmf.aspectmodel.java.ValueInitializer; @@ -89,17 +85,24 @@ import org.eclipse.esmf.metamodel.impl.DefaultCollectionValue; import org.eclipse.esmf.metamodel.impl.DefaultEntity; import org.eclipse.esmf.metamodel.impl.DefaultEntityInstance; +import org.eclipse.esmf.metamodel.impl.DefaultQuantityKind; import org.eclipse.esmf.metamodel.impl.DefaultScalar; import org.eclipse.esmf.metamodel.impl.DefaultScalarValue; import org.eclipse.esmf.metamodel.impl.DefaultUnit; import org.eclipse.esmf.metamodel.visitor.AspectVisitor; import org.eclipse.esmf.samm.KnownVersion; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.vocabulary.XSD; + public class StaticMetaModelVisitor implements AspectVisitor { private final ValueExpressionVisitor valueExpressionVisitor = new ValueExpressionVisitor(); private final ValueInitializer valueInitializer = new ValueInitializer(); - private final Supplier noTypeException = () -> new CodeGenerationException( "Characteristic is missing its dataType" ); + private final Supplier noTypeException = () -> new CodeGenerationException( + "Characteristic is missing its dataType" ); @Override public String visitBase( final ModelElement modelElement, final StaticCodeGenerationContext context ) { @@ -191,28 +194,22 @@ public String visitSingleEntity( final SingleEntity singleEntity, final StaticCo @Override public String visitCollection( final Collection collection, final StaticCodeGenerationContext context ) { - final Class implementationClass; - switch ( collection.getCollectionType() ) { - case LIST: - implementationClass = DefaultList.class; - break; - case SET: - implementationClass = DefaultSet.class; - break; - case SORTEDSET: - implementationClass = DefaultSortedSet.class; - break; - default: - implementationClass = DefaultCollection.class; - break; - } + final Class implementationClass = switch ( collection.getCollectionType() ) { + case LIST -> DefaultList.class; + case SET -> DefaultSet.class; + case SORTEDSET -> DefaultSortedSet.class; + default -> DefaultCollection.class; + }; context.getCodeGenerationConfig().importTracker().importExplicit( implementationClass ); - final String optionalType = collection.getDataType().map( type -> type.accept( this, context ) ).map( type -> "Optional.of(" + type + ")" ) + final String optionalType = collection.getDataType().map( type -> type.accept( this, context ) ) + .map( type -> "Optional.of(" + type + ")" ) .orElse( "Optional.empty()" ); - final String optionalElementCharacteristic = collection.getElementCharacteristic().map( characteristic -> characteristic.accept( this, context ) ) + final String optionalElementCharacteristic = collection.getElementCharacteristic() + .map( characteristic -> characteristic.accept( this, context ) ) .map( characteristic -> "Optional.of(" + characteristic + ")" ).orElse( "Optional.empty()" ); - return "new " + implementationClass.getSimpleName() + "(" + getMetaModelBaseAttributes( collection, context ) + "," + optionalType + "," + return "new " + implementationClass.getSimpleName() + "(" + getMetaModelBaseAttributes( collection, context ) + "," + optionalType + + "," + optionalElementCharacteristic + ")"; } @@ -285,8 +282,18 @@ public String visitUnit( final Unit unit, final StaticCodeGenerationContext cont @Override public String visitQuantityKind( final QuantityKind quantityKind, final StaticCodeGenerationContext context ) { - context.getCodeGenerationConfig().importTracker().importExplicit( QuantityKinds.class ); - return "QuantityKinds." + AspectModelJavaUtil.toConstant( quantityKind.getName() ); + // The quantity kind is one of the default ones defined in the QuantityKinds enum? + if ( QuantityKinds.fromName( quantityKind.getName() ).isPresent() ) { + context.getCodeGenerationConfig().importTracker().importExplicit( QuantityKinds.class ); + return "QuantityKinds." + AspectModelJavaUtil.toConstant( quantityKind.getName() ); + } + + // If not, create a new instance of the default implementation + context.getCodeGenerationConfig().importTracker().importExplicit( DefaultQuantityKind.class ); + return "new DefaultQuantityKind(" + + getMetaModelBaseAttributes( quantityKind, context ) + "," + + "\"" + StringEscapeUtils.escapeJava( quantityKind.getLabel() ) + "\"" + + ")"; } @Override @@ -300,7 +307,8 @@ public String visitState( final State state, final StaticCodeGenerationContext c // Type type + state.getDataType().orElseThrow( noTypeException ).accept( this, context ) + "," // List values - + "new ArrayList(){{" + state.getValues().stream().sorted().map( value -> String.format( "add(%s);", value.accept( this, context ) ) ) + + "new ArrayList(){{" + state.getValues().stream().sorted() + .map( value -> String.format( "add(%s);", value.accept( this, context ) ) ) .collect( Collectors.joining() ) + "}}," // Value defaultValue + state.getDefaultValue().accept( this, context ) + ")"; @@ -317,7 +325,8 @@ public String visitEnumeration( final Enumeration enumeration, final StaticCodeG // Type type + enumeration.getDataType().orElseThrow( noTypeException ).accept( this, context ) + "," // List values - + "new ArrayList(){{" + enumeration.getValues().stream().sorted().map( value -> String.format( "add(%s);", value.accept( this, context ) ) ) + + "new ArrayList(){{" + enumeration.getValues().stream().sorted() + .map( value -> String.format( "add(%s);", value.accept( this, context ) ) ) .collect( Collectors.joining() ) + "}})"; } @@ -334,7 +343,8 @@ public String visitStructuredValue( final StructuredValue structuredValue, final + AspectModelJavaUtil.createLiteral( structuredValue.getDeconstructionRule() ) + "," // List elements + "new ArrayList(){{" + structuredValue.getElements().stream().sequential() - .map( element -> String.format( "add(%s);", AspectModelJavaUtil.printStructuredValueElement( element ) ) ).collect( Collectors.joining() ) + "}})"; + .map( element -> String.format( "add(%s);", AspectModelJavaUtil.printStructuredValueElement( element ) ) ) + .collect( Collectors.joining() ) + "}})"; } @Override @@ -359,7 +369,8 @@ public String visitCharacteristic( final Characteristic characteristic, final St // MetaModelBaseAttributes + getMetaModelBaseAttributes( characteristic, context ) + "," // Optional type - + characteristic.getDataType().map( type -> "Optional.of(" + type.accept( this, context ) + ")" ).orElse( "Optional.empty()" ) + ")"; + + characteristic.getDataType().map( type -> "Optional.of(" + type.accept( this, context ) + ")" ).orElse( "Optional.empty()" ) + + ")"; } @Override @@ -370,9 +381,11 @@ public String visitLengthConstraint( final LengthConstraint lengthConstraint, fi // MetaModelBaseAttributes + getMetaModelBaseAttributes( lengthConstraint, context ) + "," // Optional min - + getOptionalStaticDeclarationValue( nonNegativeInteger, lengthConstraint.getMinValue(), lengthConstraint.getMetaModelVersion(), context ) + "," + + getOptionalStaticDeclarationValue( nonNegativeInteger, lengthConstraint.getMinValue(), lengthConstraint.getMetaModelVersion(), + context ) + "," // Optional max - + getOptionalStaticDeclarationValue( nonNegativeInteger, lengthConstraint.getMaxValue(), lengthConstraint.getMetaModelVersion(), context ) + ")"; + + getOptionalStaticDeclarationValue( nonNegativeInteger, lengthConstraint.getMaxValue(), lengthConstraint.getMetaModelVersion(), + context ) + ")"; } @Override @@ -384,9 +397,11 @@ public String visitRangeConstraint( final RangeConstraint rangeConstraint, final // MetaModelBaseAttributes + getMetaModelBaseAttributes( rangeConstraint, context ) + "," // Optional minValue - + getOptionalStaticDeclarationValue( characteristicType, rangeConstraint.getMinValue(), rangeConstraint.getMetaModelVersion(), context ) + "," + + getOptionalStaticDeclarationValue( characteristicType, rangeConstraint.getMinValue(), rangeConstraint.getMetaModelVersion(), + context ) + "," // Optional maxValue - + getOptionalStaticDeclarationValue( characteristicType, rangeConstraint.getMaxValue(), rangeConstraint.getMetaModelVersion(), context ) + "," + + getOptionalStaticDeclarationValue( characteristicType, rangeConstraint.getMaxValue(), rangeConstraint.getMetaModelVersion(), + context ) + "," // BoundDefinition lowerBoundDefinition + "BoundDefinition." + rangeConstraint.getLowerBoundDefinition().name() + "," // BoundDefinition upperBoundDefinition @@ -394,7 +409,8 @@ public String visitRangeConstraint( final RangeConstraint rangeConstraint, final } @Override - public String visitRegularExpressionConstraint( final RegularExpressionConstraint regularExpressionConstraint, final StaticCodeGenerationContext context ) { + public String visitRegularExpressionConstraint( final RegularExpressionConstraint regularExpressionConstraint, + final StaticCodeGenerationContext context ) { context.getCodeGenerationConfig().importTracker().importExplicit( DefaultRegularExpressionConstraint.class ); return "new DefaultRegularExpressionConstraint(" // MetaModelBaseAttributes @@ -477,7 +493,8 @@ public String visitAbstractEntity( final AbstractEntity abstractEntity, final St + extendsComplexType( abstractEntity, context ) + "," // List extendingElements + "List.of(" + abstractEntity.getExtendingElements().stream().sorted() - .map( extendingElement -> "AspectModelUrn.fromUrn(\"" + extendingElement.getUrn() + "\")" ).collect( Collectors.joining( "," ) ) + "))"; + .map( extendingElement -> "AspectModelUrn.fromUrn(\"" + extendingElement.getUrn() + "\")" ).collect( Collectors.joining( "," ) ) + + "))"; } @Override @@ -495,19 +512,23 @@ private String extendsComplexType( final ComplexType complexType, final StaticCo if ( type.is( Entity.class ) ) { final Entity entity = type.as( Entity.class ); context.getCodeGenerationConfig().importTracker().importExplicit( DefaultEntity.class ); - return "Optional.of(DefaultEntity.createDefaultEntity(" + getMetaModelBaseAttributes( complexType, context ) + "," + "Meta" + entity.getName() + return "Optional.of(DefaultEntity.createDefaultEntity(" + getMetaModelBaseAttributes( complexType, context ) + "," + "Meta" + + entity.getName() + ".INSTANCE.getProperties()," + extendsComplexType( entity, context ) + "))"; } // AbstractEntity final AbstractEntity abstractEntity = type.as( AbstractEntity.class ); context.getCodeGenerationConfig().importTracker().importExplicit( DefaultAbstractEntity.class ); - return "Optional.of(DefaultAbstractEntity.createDefaultAbstractEntity(" + getMetaModelBaseAttributes( abstractEntity, context ) + "," + "Meta" + return "Optional.of(DefaultAbstractEntity.createDefaultAbstractEntity(" + getMetaModelBaseAttributes( abstractEntity, context ) + "," + + "Meta" + abstractEntity.getName() + ".INSTANCE.getProperties()," + extendsComplexType( abstractEntity, context ) + "," + "List.of(" + abstractEntity.getExtendingElements().stream().sorted() - .map( extendingElement -> "AspectModelUrn.fromUrn( \"" + extendingElement.getUrn() + "\" )" ).collect( Collectors.joining( "," ) ) + ")" + "))"; + .map( extendingElement -> "AspectModelUrn.fromUrn( \"" + extendingElement.getUrn() + "\" )" ) + .collect( Collectors.joining( "," ) ) + ")" + "))"; } - private String getOptionalStaticDeclarationValue( final Type type, final Optional optionalValue, final KnownVersion metaModelVersion, + private String getOptionalStaticDeclarationValue( final Type type, final Optional optionalValue, + final KnownVersion metaModelVersion, final StaticCodeGenerationContext context ) { if ( optionalValue.isEmpty() ) { return "Optional.empty()"; @@ -538,9 +559,11 @@ public String metaModelBaseAttributes( final Property property, final StaticCode return getMetaModelBaseAttributes( property, context ); } - public String getMetaModelBaseAttributes( final T element, final StaticCodeGenerationContext context ) { + public String getMetaModelBaseAttributes( final T element, + final StaticCodeGenerationContext context ) { if ( element.getPreferredNames().isEmpty() && element.getDescriptions().isEmpty() && element.getSee().isEmpty() ) { - return "MetaModelBaseAttributes.from(" + "KnownVersion." + element.getMetaModelVersion().toString() + ", " + elementUrn( element, context ) + ", " + return "MetaModelBaseAttributes.from(" + "KnownVersion." + element.getMetaModelVersion().toString() + ", " + elementUrn( element, + context ) + ", " + "\"" + element.getName() + "\" )"; } @@ -549,14 +572,17 @@ public String getMetaModelBaseAttributes builder.append( ".withMetaModelVersion(KnownVersion." ).append( element.getMetaModelVersion().toString() ).append( ")" ); builder.append( ".withUrn(" ).append( elementUrn( element, context ) ).append( ")" ); element.getPreferredNames().stream().sorted().forEach( preferredName -> { - builder.append( ".withPreferredName(Locale.forLanguageTag(\"" ).append( preferredName.getLanguageTag().toLanguageTag() ).append( "\")," ); + builder.append( ".withPreferredName(Locale.forLanguageTag(\"" ).append( preferredName.getLanguageTag().toLanguageTag() ) + .append( "\")," ); builder.append( AspectModelJavaUtil.createLiteral( preferredName.getValue() ) ).append( ")" ); } ); element.getDescriptions().stream().sorted().forEach( description -> { - builder.append( ".withDescription(Locale.forLanguageTag(\"" ).append( description.getLanguageTag().toLanguageTag() ).append( "\")," ); + builder.append( ".withDescription(Locale.forLanguageTag(\"" ).append( description.getLanguageTag().toLanguageTag() ) + .append( "\")," ); builder.append( AspectModelJavaUtil.createLiteral( description.getValue() ) ).append( ")" ); } ); - element.getSee().stream().sorted().forEach( see -> builder.append( ".withSee(" ).append( AspectModelJavaUtil.createLiteral( see ) ).append( ")" ) ); + element.getSee().stream().sorted() + .forEach( see -> builder.append( ".withSee(" ).append( AspectModelJavaUtil.createLiteral( see ) ).append( ")" ) ); builder.append( ".build()" ); return builder.toString(); }