Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify ENUM usage #5

Open
dglachs opened this issue Jul 26, 2022 · 1 comment
Open

Simplify ENUM usage #5

dglachs opened this issue Jul 26, 2022 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@dglachs
Copy link

dglachs commented Jul 26, 2022

Hello all,

this is a proposal for improvement ...

currently, the generation of enums simply transforms the name of the class name to a SCREAMING_SNAKE_CASE notation. During de/serialization an extra Serializer/Deserializer has to take care of again transforming the SCREAMING_SNAKE_CASE into the serialization value (CamelCase), e.g.

ASSET_ADMINISTRATION_SHELL --> AssetAdministrationShell
SUBMODEL --> Submodel
SUBMODEL_ELEMENT --> SubmodelElement

this works well, when the transformation is always according to this transformation rule. However, this approach has several drawbacks:

  1. it does not work for the DataTypeDefXsd- Enumeration where the serialization value should be "xs:anyURI, xs:int etc."
  2. the de/serialization module wants to transform every enum, hence the configuration

module.addSerializer(Enum.class, new EnumSerializer());
cannot be used with a ObjectMapper for example with SpringBoot.

To simplify the use of enums with the AAS Model, i'd propose to keep the "serialized" value of the enumeraton such as

ASSET_ADMINISTRATION_SHELL("AssetAministrationShell") in KeyTypes or
ANY_URI("xs:anyURI") in DataTypeDefXsd

This can be achieved by changing few templates:

  • enum-default-methods.rq
  • enum-default-properties.rq
  • process-enum-individuals.rq

and by adding a new template

  • to_enum_value.rq

all of the files are attached!

changes to the distinct files are as follows:

enum-default-methods.rq

Simply generate a constructor, override the toString() method and add a static "fromValue(String text)" method. Optionally (?useJackson) add the required JsonAnnotations for @JsonValue and @JsonCreator (adopt basic-imports.rq)!

	"\n"
	"\n\t" st:call-template(idstt:to_enum_name, ?class) "(String value) {"
	"\n\t\tthis.value = value;"
	"\n\t}"
	"\n"
	"\n"
	if(?useJackson, "\n\t@JsonValue", "")
	"\n\t@Override"
	"\n\tpublic String toString() {"
	"\n\t\treturn value.toString();"
	"\n\t}"
	if(?useJackson, "\n\t@JsonCreator", "")
 	"\n\tpublic static " st:call-template(idstt:to_enum_name, ?class) " fromValue(String text) {"
	"\n\t\tfor ("st:call-template(idstt:to_enum_name, ?class) " b : " st:call-template(idstt:to_enum_name, ?class)".values()) {"
	"\n\t\t\tif (String.valueOf(b.value).equals(text)) {"
	"\n\t\t\t\treturn b;"
	"\n\t\t\t}"
	"\n\t\t}"
	"\n\t\treturn null;"
  	"\n\t}"

enum-default-properties.rq

add the member variable "value".

	"\n"
	"\n\tprivate String value;"

process-enum-individuals.rq

use the constructor and add the value, here the template providing the enum's value is called!

"\t" ucase(replace(st:call-template(idstt:to_class_name, ?individual), "([a-z])([A-Z])", CONCAT("$1", "_", "$2")))
"(\""
st:call-template(idstt:to_enum_value, ?individual)
"\"),"

to_enum_value.rq

This template checks whether the parent is DataTypeDefXsd and constructs the respective name, taking into account that the definition is named AnyUri (not AnyURI) and the first character is lowercase ...
in all other cases, the name of the class is used.

prefix idstt: <https://w3id.org/idsa/transformationtemplates/>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix aas: <https://admin-shell.io/aas/3/0/RC02/>
prefix def: <https://admin-shell.io/aas/3/0/RC02/DataTypeDefXsd/>

template idstt:to_enum_value(?class) {
	 
	if ( str(?parent) = str(<aas:DataTypeDefXsd>), 
		if (str(?class) = str(<def:AnyUri>), "xs:anyURI", 
			CONCAT("xs:", LCASE( SUBSTR( ?localName, 1, 1)), SUBSTR( ?localName, 2))
		),
		st:call-template(idstt:to_class_name, ?class)
	)

}
where {
	?class rdf:type ?parent . 
	BIND( st:call-template(idstt:to_class_name, ?class) AS ?localName)
}

Mixin instead of EnumSerializer/EnumDeserializer

using a mixin-class for each of the enums does the job. As a result, the EnumSerializer or Deserializer can be omitted

public abstract class AASEnumMixin<T> {
	@JsonValue
	public abstract String toString();
	@JsonCreator
	public abstract T fromValue(String text);
}

AASEnumGeneration.zip

@twebermartins twebermartins moved this to 🆕 New in Eclipse AAS4J Dev Oct 24, 2022
@twebermartins twebermartins added the bug Something isn't working label Dec 13, 2022
@twebermartins twebermartins moved this from 🆕 New to 📋 Backlog in Eclipse AAS4J Dev Jan 10, 2023
@twebermartins twebermartins moved this from 📋 Backlog to 🆕 New in Eclipse AAS4J Dev Jan 10, 2023
@sebbader-sap
Copy link

Hi @dglachs , first of all, really sorry for not answering earlier. It looks like I completely lost track of this issue.

According to the proposed content: Looks great! I'll prepare a feature branch soon and check how it works with the current state of the generator and the V3.0 AAS metamodel version.

(And, by the way, pretty impressive that you were able to go through the templates just by yourself!)

@sebbader-sap sebbader-sap moved this from 🆕 New to 🏗 In progress in Eclipse AAS4J Dev Aug 1, 2023
@twebermartins twebermartins moved this from 🏗 In progress to 📋 Backlog in Eclipse AAS4J Dev Oct 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: 📋 Backlog
Development

No branches or pull requests

3 participants