You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2021/10/08 12:41:16 UTC
[plc4x] branch feature/mspec-ng updated: - Replaced float syntax
with only one bitLength - Started implementing the DataReader,
DataWriter and FieldReaders - Added a new java-ng template module
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/mspec-ng
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/mspec-ng by this push:
new a740d81 - Replaced float syntax with only one bitLength - Started implementing the DataReader, DataWriter and FieldReaders - Added a new java-ng template module
a740d81 is described below
commit a740d813b1d41dc6c6ea91621fce28455f53d269
Author: cdutz <ch...@c-ware.de>
AuthorDate: Fri Oct 8 14:41:04 2021 +0200
- Replaced float syntax with only one bitLength
- Started implementing the DataReader, DataWriter and FieldReaders
- Added a new java-ng template module
---
code-generation/language-java-ng/pom.xml | 155 ++++
.../plc4x/language/java/JavaLanguageOutput.java | 100 +++
.../language/java/JavaLanguageTemplateHelper.java | 992 +++++++++++++++++++++
...x.plugins.codegenerator.language.LanguageOutput | 19 +
.../templates/java/data-io-template.java.ftlh | 425 +++++++++
.../java/enum-package-info-template.java.ftlh | 50 ++
.../templates/java/enum-template.java.ftlh | 144 +++
.../resources/templates/java/io-template.java.ftlh | 936 +++++++++++++++++++
.../templates/java/pojo-template.java.ftlh | 394 ++++++++
.../src/test/resources/integration-test/pom.xml | 207 +++++
.../src/test/resources/settings.xml | 53 ++
code-generation/pom.xml | 1 +
.../plugins/codegenerator/language/mspec/MSpec.g4 | 4 +-
.../src/main/resources/protocols/test/test.mspec | 54 +-
.../plc4x/java/spi/codegen/FieldCommons.java | 67 ++
.../apache/plc4x/java/spi/codegen/WithOption.java | 50 ++
.../plc4x/java/spi/codegen/fields/FieldReader.java | 31 +
.../spi/codegen/fields/FieldReaderAbstract.java | 37 +
.../java/spi/codegen/fields/FieldReaderArray.java | 37 +
.../java/spi/codegen/fields/FieldReaderAssert.java | 37 +
.../spi/codegen/fields/FieldReaderChecksum.java | 37 +
.../java/spi/codegen/fields/FieldReaderConst.java | 37 +
.../codegen/fields/FieldReaderDiscriminator.java | 37 +
.../java/spi/codegen/fields/FieldReaderEnum.java | 37 +
.../spi/codegen/fields/FieldReaderImplicit.java | 37 +
.../java/spi/codegen/fields/FieldReaderManual.java | 37 +
.../spi/codegen/fields/FieldReaderManualArray.java | 37 +
.../spi/codegen/fields/FieldReaderOptional.java | 53 ++
.../spi/codegen/fields/FieldReaderPadding.java | 37 +
.../spi/codegen/fields/FieldReaderReserved.java | 37 +
.../java/spi/codegen/fields/FieldReaderSimple.java | 32 +
.../spi/codegen/fields/FieldReaderTypeSwitch.java | 37 +
.../spi/codegen/fields/FieldReaderUnknown.java | 37 +
.../spi/codegen/fields/FieldReaderVirtual.java | 37 +
.../plc4x/java/spi/codegen/fields/FieldWriter.java | 28 +
.../plc4x/java/spi/codegen/io/DataReader.java | 35 +
.../java/spi/codegen/io/DataReaderComplex.java | 30 +
.../spi/codegen/io/DataReaderComplexDefault.java | 60 ++
.../plc4x/java/spi/codegen/io/DataReaderEnum.java | 28 +
.../java/spi/codegen/io/DataReaderEnumDefault.java | 57 ++
.../java/spi/codegen/io/DataReaderSimple.java | 31 +
.../spi/codegen/io/DataReaderSimpleBigDecimal.java | 46 +
.../spi/codegen/io/DataReaderSimpleBoolean.java | 48 +
.../java/spi/codegen/io/DataReaderSimpleByte.java | 46 +
.../spi/codegen/io/DataReaderSimpleByteArray.java | 46 +
.../spi/codegen/io/DataReaderSimpleDouble.java | 43 +
.../java/spi/codegen/io/DataReaderSimpleFloat.java | 43 +
.../io/DataReaderSimpleSignedBigInteger.java | 45 +
.../spi/codegen/io/DataReaderSimpleSignedByte.java | 43 +
.../spi/codegen/io/DataReaderSimpleSignedInt.java | 43 +
.../spi/codegen/io/DataReaderSimpleSignedLong.java | 43 +
.../codegen/io/DataReaderSimpleSignedShort.java | 43 +
.../io/DataReaderSimpleUnsignedBigInteger.java | 45 +
.../codegen/io/DataReaderSimpleUnsignedByte.java | 43 +
.../codegen/io/DataReaderSimpleUnsignedInt.java | 43 +
.../codegen/io/DataReaderSimpleUnsignedLong.java | 43 +
.../codegen/io/DataReaderSimpleUnsignedShort.java | 43 +
.../plc4x/java/spi/codegen/io/DataWriter.java | 27 +
.../java/spi/codegen/io/DataWriterBigDecimal.java | 39 +
.../java/spi/codegen/io/DataWriterBoolean.java | 41 +
.../plc4x/java/spi/codegen/io/DataWriterByte.java | 41 +
.../java/spi/codegen/io/DataWriterByteArray.java | 42 +
.../java/spi/codegen/io/DataWriterDouble.java | 38 +
.../plc4x/java/spi/codegen/io/DataWriterFloat.java | 40 +
.../spi/codegen/io/DataWriterSignedBigInteger.java | 39 +
.../java/spi/codegen/io/DataWriterSignedByte.java | 38 +
.../java/spi/codegen/io/DataWriterSignedInt.java | 38 +
.../java/spi/codegen/io/DataWriterSignedLong.java | 38 +
.../java/spi/codegen/io/DataWriterSignedShort.java | 38 +
.../codegen/io/DataWriterUnsignedBigInteger.java | 39 +
.../spi/codegen/io/DataWriterUnsignedByte.java | 38 +
.../java/spi/codegen/io/DataWriterUnsignedInt.java | 38 +
.../spi/codegen/io/DataWriterUnsignedLong.java | 38 +
.../java/spi/generation/WriteBufferByteBased.java | 12 +-
.../java/spi/generation/WriteBufferJsonBased.java | 6 +-
.../java/spi/generation/WriteBufferXmlBased.java | 7 +-
.../org/apache/plc4x/java/spi/values/PlcLREAL.java | 3 +-
.../org/apache/plc4x/java/spi/values/PlcREAL.java | 3 +-
.../ads/src/main/resources/protocols/ads/ads.mspec | 4 +-
.../resources/protocols/bacnetip/bacnetip.mspec | 8 +-
.../src/main/resources/protocols/can/canopen.mspec | 4 +-
.../main/resources/protocols/can/genericcan.mspec | 4 +-
.../resources/protocols/knxnetip/knxnetip.mspec | 6 +-
.../main/resources/protocols/modbus/modbus.mspec | 8 +-
.../s7/src/main/resources/protocols/s7/s7.mspec | 4 +-
.../resources/protocols/simulated/simulated.mspec | 8 +-
86 files changed, 5915 insertions(+), 71 deletions(-)
diff --git a/code-generation/language-java-ng/pom.xml b/code-generation/language-java-ng/pom.xml
new file mode 100644
index 0000000..7d51745
--- /dev/null
+++ b/code-generation/language-java-ng/pom.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>plc4x-code-generation-language-java-ng</artifactId>
+
+ <name>Code-Generation: Language: Java</name>
+ <description>Code generation template for generating Java code</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>3.2.2</version>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <!-- Install the current project artifacts into the maven local repo, so they can be used in the test -->
+ <goal>install</goal>
+ <!-- Execute the maven builds defines in src/test/resources -->
+ <goal>integration-test</goal>
+ <!-- Checks the results of the maven builds -->
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <!-- These option allow that openjdk >=16 can run the google-code-format -->
+ <!-- TODO: Add this to a self-activating maven profile -->
+ <!--mavenOpts>
+ - -add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+ - -add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
+ - -add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
+ - -add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
+ - -add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
+ </mavenOpts-->
+ <debug>true</debug>
+ <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+ <projectsDirectory>src/test/resources</projectsDirectory>
+ <cloneProjectsTo>${project.build.directory}/integration-tests</cloneProjectsTo>
+ <settingsFile>src/test/resources/settings.xml</settingsFile>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <!-- The goals we will be executing in the test-projects -->
+ <goals>
+ <goal>test</goal>
+ </goals>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <!-- We are using the Freemarker module to generate Java code -->
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-language-base-freemarker</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-code-generation-types-base</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-text</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-base-mspec</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.googlejavaformat</groupId>
+ <artifactId>google-java-format</artifactId>
+ <version>1.11.0</version>
+ </dependency>
+
+ <!-- Make sure the dependencies of the module are built first -->
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-api</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-spi</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-transport-tcp</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-utils-test-utils</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-test</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-test</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <classifier>tests</classifier>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java b/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
new file mode 100644
index 0000000..f935fcc
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.language.java;
+
+import com.google.googlejavaformat.java.FormatterException;
+import freemarker.template.*;
+import org.apache.commons.io.FileUtils;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageOutput;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.*;
+
+import com.google.googlejavaformat.java.Formatter;
+
+public class JavaLanguageOutput extends FreemarkerLanguageOutput {
+
+ private Formatter formatter = new Formatter();
+
+ @Override
+ public String getName() {
+ return "Java";
+ }
+
+ @Override
+ public Set<String> supportedOptions() {
+ return Collections.singleton("package");
+ }
+
+ @Override
+ public List<String> supportedOutputFlavors() {
+ return Arrays.asList("read-write", "read-only", "passive");
+ }
+
+ @Override
+ protected List<Template> getSpecTemplates(Configuration freemarkerConfiguration) throws IOException {
+ return Collections.singletonList(
+ freemarkerConfiguration.getTemplate("templates/java/enum-package-info-template.java.ftlh"));
+ }
+
+ @Override
+ protected List<Template> getComplexTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
+ return Arrays.asList(
+ freemarkerConfiguration.getTemplate("templates/java/pojo-template.java.ftlh"),
+ freemarkerConfiguration.getTemplate("templates/java/io-template.java.ftlh"));
+ }
+
+ @Override
+ protected List<Template> getEnumTypeTemplates(Configuration freemarkerConfiguration) throws IOException {
+ return Collections.singletonList(
+ freemarkerConfiguration.getTemplate("templates/java/enum-template.java.ftlh"));
+ }
+
+ @Override
+ protected List<Template> getDataIoTemplates(Configuration freemarkerConfiguration) throws IOException {
+ return Collections.singletonList(
+ freemarkerConfiguration.getTemplate("templates/java/data-io-template.java.ftlh"));
+ }
+
+ @Override
+ protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+ Map<String, String> options) {
+ return new JavaLanguageTemplateHelper(thisType, protocolName, flavorName, types, options);
+ }
+
+ @Override
+ protected void postProcessTemplateOutput(File outputFile) {
+ try {
+ FileUtils.writeStringToFile(
+ outputFile,
+ formatter.formatSourceAndFixImports(
+ FileUtils.readFileToString(outputFile, StandardCharsets.UTF_8)
+ ),
+ StandardCharsets.UTF_8
+ );
+ } catch (IOException | FormatterException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
new file mode 100644
index 0000000..686b3f7
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -0,0 +1,992 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.language.java;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.commons.text.WordUtils;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException;
+import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
+import org.apache.plc4x.plugins.codegenerator.types.fields.*;
+import org.apache.plc4x.plugins.codegenerator.types.references.*;
+import org.apache.plc4x.plugins.codegenerator.types.terms.*;
+
+import java.util.Map;
+import java.util.function.Function;
+
+@SuppressWarnings({"unused", "WeakerAccess"})
+public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
+
+ private final Map<String, String> options;
+
+ public JavaLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+ Map<String, String> options) {
+ super(thisType, protocolName, flavorName, types);
+ this.options = options;
+ }
+
+ public String packageName(String protocolName, String languageName, String languageFlavorName) {
+ return Optional.ofNullable(options.get("package")).orElseGet(() ->
+ "org.apache.plc4x." + String.join("", languageName.split("\\-")) + "." +
+ String.join("", protocolName.split("\\-")) + "." +
+ String.join("", languageFlavorName.split("\\-")));
+ }
+
+ @Override
+ public String getLanguageTypeNameForField(Field field) {
+ boolean optional = field instanceof OptionalField;
+ // If the referenced type is a DataIo type, the value is of type PlcValue.
+ if (field instanceof PropertyField) {
+ PropertyField propertyField = (PropertyField) field;
+ if (propertyField.getType() instanceof ComplexTypeReference) {
+ ComplexTypeReference complexTypeReference = (ComplexTypeReference) propertyField.getType();
+ final TypeDefinition typeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
+ if (typeDefinition instanceof DataIoTypeDefinition) {
+ return "PlcValue";
+ }
+ }
+ }
+ return getLanguageTypeNameForTypeReference(((TypedField) field).getType(), !optional);
+ }
+
+ public String getNonPrimitiveLanguageTypeNameForField(TypedField field) {
+ return getLanguageTypeNameForTypeReference(field.getType(), false);
+ }
+
+ public String getLanguageTypeNameForSpecType(TypeReference typeReference) {
+ return getLanguageTypeNameForTypeReference(typeReference, true);
+ }
+
+ @Override
+ public String getLanguageTypeNameForTypeReference(TypeReference typeReference) {
+ return getLanguageTypeNameForTypeReference(typeReference, false);
+ }
+
+ public String adjustLiterals(String javaType, String value) {
+ switch (javaType) {
+ case "long":
+ case "Long":
+ return value + "L";
+ default:
+ return value;
+ }
+ }
+
+ public String getLanguageTypeNameForTypeReference(TypeReference typeReference, boolean allowPrimitive) {
+ if (typeReference instanceof SimpleTypeReference) {
+ SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+ switch (simpleTypeReference.getBaseType()) {
+ case BIT:
+ return allowPrimitive ? boolean.class.getSimpleName() : Boolean.class.getSimpleName();
+ case BYTE:
+ return allowPrimitive ? byte.class.getSimpleName() : Byte.class.getSimpleName();
+ case UINT:
+ IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
+ return allowPrimitive ? byte.class.getSimpleName() : Byte.class.getSimpleName();
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+ return allowPrimitive ? short.class.getSimpleName() : Short.class.getSimpleName();
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+ return allowPrimitive ? int.class.getSimpleName() : Integer.class.getSimpleName();
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+ return allowPrimitive ? long.class.getSimpleName() : Long.class.getSimpleName();
+ }
+ return BigInteger.class.getSimpleName();
+ case INT:
+ IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (integerTypeReference.getSizeInBits() <= 8) {
+ return allowPrimitive ? byte.class.getSimpleName() : Byte.class.getSimpleName();
+ }
+ if (integerTypeReference.getSizeInBits() <= 16) {
+ return allowPrimitive ? short.class.getSimpleName() : Short.class.getSimpleName();
+ }
+ if (integerTypeReference.getSizeInBits() <= 32) {
+ return allowPrimitive ? int.class.getSimpleName() : Integer.class.getSimpleName();
+ }
+ if (integerTypeReference.getSizeInBits() <= 64) {
+ return allowPrimitive ? long.class.getSimpleName() : Long.class.getSimpleName();
+ }
+ return BigInteger.class.getSimpleName();
+ case FLOAT:
+ case UFLOAT:
+ FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+ int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
+ floatTypeReference.getExponent() + floatTypeReference.getMantissa();
+ if (sizeInBits <= 32) {
+ return allowPrimitive ? float.class.getSimpleName() : Float.class.getSimpleName();
+ }
+ if (sizeInBits <= 64) {
+ return allowPrimitive ? double.class.getSimpleName() : Double.class.getSimpleName();
+ }
+ return BigDecimal.class.getSimpleName();
+ case STRING:
+ case VSTRING:
+ return String.class.getSimpleName();
+ case TIME:
+ return LocalTime.class.getSimpleName();
+ case DATE:
+ return LocalDate.class.getSimpleName();
+ case DATETIME:
+ return LocalDateTime.class.getSimpleName();
+
+ }
+ throw new RuntimeException("Unsupported simple type");
+ } else {
+ return ((ComplexTypeReference) typeReference).getName();
+ }
+ }
+
+ public String getPlcValueTypeForTypeReference(TypeReference typeReference) {
+ if (typeReference instanceof SimpleTypeReference) {
+ SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+ switch (simpleTypeReference.getBaseType()) {
+ case BIT:
+ return "PlcBOOL";
+ case BYTE:
+ return "PlcSINT";
+ case UINT:
+ IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
+ return "PlcUSINT";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+ return "PlcUINT";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+ return "PlcUDINT";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+ return "PlcULINT";
+ }
+ case INT:
+ IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (integerTypeReference.getSizeInBits() <= 8) {
+ return "PlcSINT";
+ }
+ if (integerTypeReference.getSizeInBits() <= 16) {
+ return "PlcINT";
+ }
+ if (integerTypeReference.getSizeInBits() <= 32) {
+ return "PlcDINT";
+ }
+ if (integerTypeReference.getSizeInBits() <= 64) {
+ return "PlcLINT";
+ }
+
+ case FLOAT:
+ case UFLOAT:
+ FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+ int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
+ floatTypeReference.getExponent() + floatTypeReference.getMantissa();
+ if (sizeInBits <= 32) {
+ return "PlcREAL";
+ }
+ if (sizeInBits <= 64) {
+ return "PlcLREAL";
+ }
+ case STRING:
+ case VSTRING:
+ return "PlcSTRING";
+ case TIME:
+ case DATE:
+ case DATETIME:
+ return "PlcTIME";
+ }
+ throw new RuntimeException("Unsupported simple type");
+ } else {
+ return "PlcStruct";
+ }
+ }
+
+ @Override
+ public String getNullValueForTypeReference(TypeReference typeReference) {
+ if (typeReference instanceof SimpleTypeReference) {
+ SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+ switch (simpleTypeReference.getBaseType()) {
+ case BIT:
+ return "false";
+ case BYTE:
+ return "0";
+ case UINT:
+ IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+ return "0";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+ return "0l";
+ }
+ return "null";
+ case INT:
+ IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (integerTypeReference.getSizeInBits() <= 32) {
+ return "0";
+ }
+ if (integerTypeReference.getSizeInBits() <= 64) {
+ return "0l";
+ }
+ return "null";
+ case FLOAT:
+ FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+ int sizeInBits = ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? 1 : 0) +
+ floatTypeReference.getExponent() + floatTypeReference.getMantissa();
+ if (sizeInBits <= 32) {
+ return "0.0f";
+ }
+ if (sizeInBits <= 64) {
+ return "0.0";
+ }
+ return "null";
+ case STRING:
+ case VSTRING:
+ return "null";
+ }
+ throw new FreemarkerException("Unmapped basetype" + simpleTypeReference.getBaseType());
+ } else {
+ return "null";
+ }
+ }
+
+ /*public String getArgumentType(TypeReference typeReference, int index) {
+ if(typeReference instanceof ComplexTypeReference) {
+ ComplexTypeReference complexTypeReference = (ComplexTypeReference) typeReference;
+ if(!getTypeDefinitions().containsKey(complexTypeReference.getName())) {
+ throw new RuntimeException("Could not find definition of complex type " + complexTypeReference.getName());
+ }
+ TypeDefinition complexTypeDefinition = getTypeDefinitions().get(complexTypeReference.getName());
+ if(complexTypeDefinition.getParserArguments().length <= index) {
+ throw new RuntimeException("Type " + complexTypeReference.getName() + " specifies too few parser arguments");
+ }
+ return getLanguageTypeNameForSpecType(complexTypeDefinition.getParserArguments()[index].getType());
+ }
+ return "Hurz";
+ }*/
+
+ public int getNumBits(SimpleTypeReference simpleTypeReference) {
+ switch (simpleTypeReference.getBaseType()) {
+ case BIT:
+ return 1;
+ case BYTE:
+ return 8;
+ case UINT:
+ case INT:
+ IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ return integerTypeReference.getSizeInBits();
+ case FLOAT:
+ FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+ return floatTypeReference.getSizeInBits();
+ case STRING:
+ case VSTRING:
+ StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
+ return stringTypeReference.getSizeInBits();
+ default:
+ return 0;
+ }
+ }
+
+ @Override
+ public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
+ return getReadBufferReadMethodCall("", simpleTypeReference, valueString, field);
+ }
+
+ public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String valueString, TypedField field) {
+ switch (simpleTypeReference.getBaseType()) {
+ case BIT:
+ return "readBuffer.readBit(\"" + logicalName + "\")";
+ case BYTE:
+ ByteTypeReference byteTypeReference = (ByteTypeReference) simpleTypeReference;
+ return "readBuffer.readByte(\"" + logicalName + "\")";
+ case UINT:
+ IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
+ return "readBuffer.readUnsignedByte(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ")";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+ return "readBuffer.readUnsignedShort(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ")";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+ return "readBuffer.readUnsignedInt(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ")";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+ return "readBuffer.readUnsignedLong(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ")";
+ }
+ return "readBuffer.readUnsignedBigInteger(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ")";
+ case INT:
+ IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (integerTypeReference.getSizeInBits() <= 8) {
+ return "readBuffer.readSignedByte(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ")";
+ }
+ if (integerTypeReference.getSizeInBits() <= 16) {
+ return "readBuffer.readShort(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ")";
+ }
+ if (integerTypeReference.getSizeInBits() <= 32) {
+ return "readBuffer.readInt(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ")";
+ }
+ if (integerTypeReference.getSizeInBits() <= 64) {
+ return "readBuffer.readLong(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ")";
+ }
+ return "readBuffer.readBigInteger(" + integerTypeReference.getSizeInBits() + ")";
+ case FLOAT:
+ FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+ String type = (floatTypeReference.getSizeInBits() <= 32) ? "Float" : "Double";
+ String typeCast = (floatTypeReference.getSizeInBits() <= 32) ? "float" : "double";
+ String defaultNull = (floatTypeReference.getSizeInBits() <= 32) ? "0.0f" : "0.0";
+ return "((Supplier<" + type + ">) (() -> {" +
+ "\n return (" + typeCast + ") toFloat(readBuffer, \"" + logicalName + "\", " +
+ ((floatTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.FLOAT) ? "true" : "false") +
+ ", " + floatTypeReference.getExponent() + ", " +
+ floatTypeReference.getMantissa() + ");" +
+ "\n })).get()";
+ case STRING:
+ case VSTRING:
+ StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
+ return "readBuffer.readString(\"" + logicalName + "\", " + toParseExpression(field, stringTypeReference.getLengthExpression(), null) + ", \"" +
+ stringTypeReference.getEncoding() + "\")";
+ }
+ return "";
+ }
+
+ @Override
+ public String getWriteBufferWriteMethodCall(SimpleTypeReference simpleTypeReference, String fieldName, TypedField field) {
+ return getWriteBufferWriteMethodCall("", simpleTypeReference, fieldName, field);
+ }
+
+ public String getWriteBufferWriteMethodCall(String logicalName, SimpleTypeReference simpleTypeReference, String fieldName, TypedField field, String... writerArgs) {
+ String writerArgsString = "";
+ if (writerArgs.length > 0) {
+ writerArgsString += ", " + StringUtils.join(writerArgs, ", ");
+ }
+ switch (simpleTypeReference.getBaseType()) {
+ case BIT:
+ return "writeBuffer.writeBit(\"" + logicalName + "\", (boolean) " + fieldName + "" + writerArgsString + ")";
+ case BYTE:
+ ByteTypeReference byteTypeReference = (ByteTypeReference) simpleTypeReference;
+ return "writeBuffer.writeByte(\"" + logicalName + "\", ((Number) " + fieldName + ").byteValue()" + writerArgsString + ")";
+ case UINT:
+ IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
+ return "writeBuffer.writeUnsignedByte(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").byteValue()" + writerArgsString + ")";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
+ return "writeBuffer.writeUnsignedShort(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").shortValue()" + writerArgsString + ")";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 16) {
+ return "writeBuffer.writeUnsignedInt(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").intValue()" + writerArgsString + ")";
+ }
+ if (unsignedIntegerTypeReference.getSizeInBits() <= 32) {
+ return "writeBuffer.writeUnsignedLong(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").longValue()" + writerArgsString + ")";
+ }
+ return "writeBuffer.writeUnsignedBigInteger(\"" + logicalName + "\", " + unsignedIntegerTypeReference.getSizeInBits() + ", (BigInteger) " + fieldName + "" + writerArgsString + ")";
+ case INT:
+ IntegerTypeReference integerTypeReference = (IntegerTypeReference) simpleTypeReference;
+ if (integerTypeReference.getSizeInBits() <= 8) {
+ return "writeBuffer.writeSignedByte(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").byteValue()" + writerArgsString + ")";
+ }
+ if (integerTypeReference.getSizeInBits() <= 16) {
+ return "writeBuffer.writeShort(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").shortValue()" + writerArgsString + ")";
+ }
+ if (integerTypeReference.getSizeInBits() <= 32) {
+ return "writeBuffer.writeInt(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").intValue()" + writerArgsString + ")";
+ }
+ if (integerTypeReference.getSizeInBits() <= 64) {
+ return "writeBuffer.writeLong(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", ((Number) " + fieldName + ").longValue()" + writerArgsString + ")";
+ }
+ return "writeBuffer.writeBigInteger(\"" + logicalName + "\", " + integerTypeReference.getSizeInBits() + ", BigInteger.valueOf( " + fieldName + ")" + writerArgsString + ")";
+ case FLOAT:
+ case UFLOAT:
+ FloatTypeReference floatTypeReference = (FloatTypeReference) simpleTypeReference;
+ if (floatTypeReference.getSizeInBits() <= 32) {
+ return "writeBuffer.writeFloat(\"" + logicalName + "\", " + fieldName + "," + floatTypeReference.getExponent() + "," + floatTypeReference.getMantissa() + "" + writerArgsString + ")";
+ } else if (floatTypeReference.getSizeInBits() <= 64) {
+ return "writeBuffer.writeDouble(\"" + logicalName + "\", " + fieldName + "," + floatTypeReference.getExponent() + "," + floatTypeReference.getMantissa() + "" + writerArgsString + ")";
+ } else {
+ throw new RuntimeException("Unsupported float type");
+ }
+ case STRING:
+ case VSTRING:
+ StringTypeReference stringTypeReference = (StringTypeReference) simpleTypeReference;
+ return "writeBuffer.writeString(\"" + logicalName + "\", " + toSerializationExpression(field, stringTypeReference.getLengthExpression(), thisType.getParserArguments().orElse(Collections.emptyList())) + ", \"" +
+ stringTypeReference.getEncoding() + "\", (String) " + fieldName + "" + writerArgsString + ")";
+ }
+ throw new FreemarkerException("Unmapped basetype" + simpleTypeReference.getBaseType());
+ }
+
+ /*public String getReadMethodName(SimpleTypeReference simpleTypeReference) {
+ String languageTypeName = getLanguageTypeNameForSpecType(simpleTypeReference);
+ languageTypeName = languageTypeName.substring(0, 1).toUpperCase() + languageTypeName.substring(1);
+ if(simpleTypeReference.getBaseType().equals(SimpleTypeReference.SimpleBaseType.UINT)) {
+ return "readUnsigned" + languageTypeName;
+ } else {
+ return "read" + languageTypeName;
+ }
+ }*/
+
+ public String getReservedValue(ReservedField reservedField) {
+ final String languageTypeName = getLanguageTypeNameForTypeReference(reservedField.getType(), true);
+ if ("BigInteger".equals(languageTypeName)) {
+ return "BigInteger.valueOf(" + reservedField.getReferenceValue() + ")";
+ } else {
+ return "(" + languageTypeName + ") " + reservedField.getReferenceValue();
+ }
+ }
+
+ /*public Collection<ComplexTypeReference> getComplexTypes(ComplexTypeDefinition complexTypeDefinition) {
+ Map<String, ComplexTypeReference> types = new HashMap<>();
+ for (Field field : complexTypeDefinition.getFields()) {
+ if(field instanceof TypedField) {
+ TypedField typedField = (TypedField) field;
+ if(typedField.getType() instanceof ComplexTypeReference) {
+ ComplexTypeReference complexTypeReference = (ComplexTypeReference) typedField.getType();
+ types.put(complexTypeReference.getName(), complexTypeReference);
+ }
+ } else if(field instanceof SwitchField) {
+ SwitchField switchField = (SwitchField) field;
+ for (DiscriminatedComplexTypeDefinition cas : switchField.getCases()) {
+ types.put(cas.getName(), new ComplexTypeReference() {
+ @Override
+ public String getName() {
+ return cas.getName();
+ }
+ });
+ }
+ }
+ }
+ return types.values();
+ }*/
+
+ /*public Collection<ComplexTypeReference> getEnumTypes(ComplexTypeDefinition complexTypeDefinition) {
+ Map<String, ComplexTypeReference> types = new HashMap<>();
+ for (Field field : complexTypeDefinition.getFields()) {
+ if(field instanceof EnumField) {
+ EnumField enumField = (EnumField) field;
+ if(enumField.getType() instanceof ComplexTypeReference) {
+ ComplexTypeReference complexTypeReference = (ComplexTypeReference) enumField.getType();
+ types.put(complexTypeReference.getName(), complexTypeReference);
+ }
+ }
+ }
+ for (Field field : complexTypeDefinition.getParentPropertyFields()) {
+ if(field instanceof EnumField) {
+ EnumField enumField = (EnumField) field;
+ if(enumField.getType() instanceof ComplexTypeReference) {
+ ComplexTypeReference complexTypeReference = (ComplexTypeReference) enumField.getType();
+ types.put(complexTypeReference.getName(), complexTypeReference);
+ }
+ }
+ }
+ return types.values();
+ }*/
+
+ public String toAccessExpression(TypedField field, Term term, List<Argument> parserArguments) {
+ return toExpression(field, term, variableLiteral -> {
+ if (isVariableLiteralVirtualField(variableLiteral) || isVariableLiteralDiscriminatorField(variableLiteral)) { // If we are accessing virtual|discriminator fields, we need to call the getter.
+ return "get" + StringUtils.capitalize(variableLiteral.getName()) + "()";
+ }
+ return toVariableParseExpression(field, variableLiteral, parserArguments);
+ });
+ }
+
+ public String toParseExpression(TypedField field, Term term, List<Argument> parserArguments) {
+ Tracer tracer = Tracer.start("toParseExpression");
+ return tracer + toExpression(field, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableParseExpression(field, variableLiteral, parserArguments));
+ }
+
+ public String toSerializationExpression(TypedField field, Term term, List<Argument> serializerArguments) {
+ Tracer tracer = Tracer.start("toSerializationExpression");
+ return tracer + toExpression(field, term, variableLiteral -> tracer.dive("variableExpressionGenerator") + toVariableSerializationExpression(field, variableLiteral, serializerArguments));
+ }
+
+ private String toExpression(TypedField field, Term term, Function<VariableLiteral, String> variableExpressionGenerator) {
+ Tracer tracer = Tracer.start("toExpression");
+ if (term == null) {
+ return tracer + "";
+ }
+ if (term instanceof Literal) {
+ return toLiteralTermExpression((Literal) term, variableExpressionGenerator, tracer);
+ } else if (term instanceof UnaryTerm) {
+ return toUnaryTermExpression(field, (UnaryTerm) term, variableExpressionGenerator, tracer);
+ } else if (term instanceof BinaryTerm) {
+ return toBinaryTermExpression(field, (BinaryTerm) term, variableExpressionGenerator, tracer);
+ } else if (term instanceof TernaryTerm) {
+ return toTernaryTermExpression(field, (TernaryTerm) term, variableExpressionGenerator, tracer);
+ } else {
+ throw new RuntimeException("Unsupported Term type " + term.getClass().getName());
+ }
+ }
+
+ private String toLiteralTermExpression(Literal literal, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+ tracer = tracer.dive("literal term instanceOf");
+ if (literal instanceof NullLiteral) {
+ tracer = tracer.dive("null literal instanceOf");
+ return tracer + "null";
+ } else if (literal instanceof BooleanLiteral) {
+ tracer = tracer.dive("boolean literal instanceOf");
+ return tracer + Boolean.toString(((BooleanLiteral) literal).getValue());
+ } else if (literal instanceof NumericLiteral) {
+ tracer = tracer.dive("numeric literal instanceOf");
+ return tracer + ((NumericLiteral) literal).getNumber().toString();
+ } else if (literal instanceof StringLiteral) {
+ tracer = tracer.dive("string literal instanceOf");
+ return tracer + "\"" + ((StringLiteral) literal).getValue() + "\"";
+ } else if (literal instanceof VariableLiteral) {
+ tracer = tracer.dive("variable literal instanceOf");
+ VariableLiteral variableLiteral = (VariableLiteral) literal;
+ // If this literal references an Enum type, then we have to output it differently.
+ if (getTypeDefinitions().get(variableLiteral.getName()) instanceof EnumTypeDefinition) {
+ tracer = tracer.dive("enum definition instanceOf");
+ VariableLiteral enumDefinitionChild = variableLiteral.getChild()
+ .orElseThrow(() -> new RuntimeException("enum definitions should have childs"));
+ return tracer + variableLiteral.getName() + "." + enumDefinitionChild.getName() +
+ enumDefinitionChild.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
+ } else {
+ return tracer + variableExpressionGenerator.apply(variableLiteral);
+ }
+ } else {
+ throw new RuntimeException("Unsupported Literal type " + literal.getClass().getName());
+ }
+ }
+
+ private String toUnaryTermExpression(TypedField field, UnaryTerm unaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+ tracer = tracer.dive("unary term instanceOf");
+ Term a = unaryTerm.getA();
+ switch (unaryTerm.getOperation()) {
+ case "!":
+ tracer = tracer.dive("case !");
+ return tracer + "!(" + toExpression(field, a, variableExpressionGenerator) + ")";
+ case "-":
+ tracer = tracer.dive("case -");
+ return tracer + "-(" + toExpression(field, a, variableExpressionGenerator) + ")";
+ case "()":
+ tracer = tracer.dive("case ()");
+ return tracer + "(" + toExpression(field, a, variableExpressionGenerator) + ")";
+ default:
+ throw new RuntimeException("Unsupported unary operation type " + unaryTerm.getOperation());
+ }
+ }
+
+ private String toBinaryTermExpression(TypedField field, BinaryTerm binaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+ tracer = tracer.dive("binary term instanceOf");
+ Term a = binaryTerm.getA();
+ Term b = binaryTerm.getB();
+ String operation = binaryTerm.getOperation();
+ switch (operation) {
+ case "^":
+ tracer = tracer.dive("^");
+ return tracer + "Math.pow((" + toExpression(field, a, variableExpressionGenerator) + "), (" + toExpression(field, b, variableExpressionGenerator) + "))";
+ default:
+ return tracer + "(" + toExpression(field, a, variableExpressionGenerator) + ") " + operation + " (" + toExpression(field, b, variableExpressionGenerator) + ")";
+ }
+ }
+
+ private String toTernaryTermExpression(TypedField field, TernaryTerm ternaryTerm, Function<VariableLiteral, String> variableExpressionGenerator, Tracer tracer) {
+ tracer = tracer.dive("ternary term instanceOf");
+ if ("if".equals(ternaryTerm.getOperation())) {
+ Term a = ternaryTerm.getA();
+ Term b = ternaryTerm.getB();
+ Term c = ternaryTerm.getC();
+ return tracer + "((" + toExpression(field, a, variableExpressionGenerator) + ") ? " + toExpression(field, b, variableExpressionGenerator) + " : " + toExpression(field, c, variableExpressionGenerator) + ")";
+ } else {
+ throw new RuntimeException("Unsupported ternary operation type " + ternaryTerm.getOperation());
+ }
+ }
+
+ public String toVariableEnumAccessExpression(VariableLiteral variableLiteral) {
+ return variableLiteral.getName();
+ }
+
+ private String toVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments) {
+ Tracer tracer = Tracer.start("toVariableParseExpression");
+ // CAST expressions are special as we need to add a ".class" to the second parameter in Java.
+ if ("CAST".equals(variableLiteral.getName())) {
+ return toCastVariableParseExpression(field, variableLiteral, parserArguments, tracer);
+ } else if ("STATIC_CALL".equals(variableLiteral.getName())) {
+ return toStaticCallVariableParseExpression(field, variableLiteral, parserArguments, tracer);
+ } else if (isVariableLiteralImplicitField(variableLiteral)) { // If we are accessing implicit fields, we need to rely on a local variable instead.
+ return toImplictVariableParseExpression(variableLiteral, tracer);
+ } else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) { // All uppercase names are not fields, but utility methods.
+ return toUpperCaseVariableParseExpression(field, variableLiteral, parserArguments, tracer);
+ }
+ return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
+ }
+
+ private String toUpperCaseVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
+ tracer = tracer.dive("UPPERCASE");
+ StringBuilder sb = new StringBuilder(variableLiteral.getName());
+ if (variableLiteral.getArgs().isPresent()) {
+ sb.append("(");
+ boolean firstArg = true;
+ for (Term arg : variableLiteral.getArgs().get()) {
+ if (!firstArg) {
+ sb.append(", ");
+ }
+ sb.append(toParseExpression(field, arg, parserArguments));
+ firstArg = false;
+ }
+ sb.append(")");
+ }
+ if (variableLiteral.getIndex() != VariableLiteral.NO_INDEX) {
+ sb.append("[").append(variableLiteral.getIndex()).append("]");
+ }
+ return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
+ }
+
+ private String toImplictVariableParseExpression(VariableLiteral variableLiteral, Tracer tracer) {
+ tracer = tracer.dive("implicit");
+ return tracer + variableLiteral.getName();
+ }
+
+ private String toStaticCallVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
+ tracer = tracer.dive("STATIC_CALL");
+ StringBuilder sb = new StringBuilder();
+ List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+ if (arguments.size() < 1) {
+ throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
+ }
+ // Get the class and method name
+ String methodName = arguments.get(0).asLiteral()
+ .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+ .asStringLiteral()
+ .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+ getValue();
+ // Cut off the double-quotes
+ methodName = methodName.substring(1, methodName.length() - 1);
+ sb.append(methodName).append("(");
+ for (int i = 1; i < arguments.size(); i++) {
+ Term arg = arguments.get(i);
+ if (i > 1) {
+ sb.append(", ");
+ }
+ if (arg instanceof VariableLiteral) {
+ VariableLiteral variableLiteralArg = (VariableLiteral) arg;
+ // "readBuffer" is the default name of the reader argument which is always available.
+ boolean isParserArg = "readBuffer".equals(variableLiteralArg.getName());
+ boolean isTypeArg = "_type".equals(variableLiteralArg.getName());
+ if (!isParserArg && !isTypeArg && parserArguments != null) {
+ for (Argument parserArgument : parserArguments) {
+ if (parserArgument.getName().equals(variableLiteralArg.getName())) {
+ isParserArg = true;
+ break;
+ }
+ }
+ }
+ if (isParserArg) {
+ sb.append(variableLiteralArg.getName()).append(variableLiteralArg.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+ } else if (isTypeArg) {// We have to manually evaluate the type information at code-generation time.
+ String part = variableLiteralArg.getChild().map(VariableLiteral::getName).orElse("");
+ switch (part) {
+ case "name":
+ sb.append("\"").append(field.getTypeName()).append("\"");
+ break;
+ case "length":
+ sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+ break;
+ case "encoding":
+ String encoding = ((StringTypeReference) field.getType()).getEncoding();
+ // Cut off the single quotes.
+ encoding = encoding.substring(1, encoding.length() - 1);
+ sb.append("\"").append(encoding).append("\"");
+ break;
+ }
+ } else {
+ sb.append(toVariableParseExpression(field, variableLiteralArg, null));
+ }
+ } else if (arg instanceof StringLiteral) {
+ sb.append(((StringLiteral) arg).getValue());
+ }
+ }
+ sb.append(")");
+ return tracer + sb.toString();
+ }
+
+ private String toCastVariableParseExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> parserArguments, Tracer tracer) {
+ tracer = tracer.dive("CAST");
+ StringBuilder sb = new StringBuilder(variableLiteral.getName());
+ List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A Cast expression needs arguments"));
+ if (arguments.size() != 2) {
+ throw new RuntimeException("A CAST expression expects exactly two arguments.");
+ }
+ VariableLiteral firstArgument = arguments.get(0).asLiteral()
+ .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+ .asVariableLiteral()
+ .orElseThrow(() -> new RuntimeException("First argument should be a Variable literal"));
+ VariableLiteral secondArgument = arguments.get(1).asLiteral().orElseThrow(() -> new RuntimeException("Second argument should be a literal"))
+ .asVariableLiteral()
+ .orElseThrow(() -> new RuntimeException("Second argument should be a Variable literal"));
+ sb.append("(")
+ .append(toVariableParseExpression(field, firstArgument, parserArguments))
+ .append(", ")
+ .append(secondArgument.getName()).append(".class)");
+ return tracer + sb.toString() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
+ }
+
+ private String toVariableSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments) {
+ Tracer tracer = Tracer.start("variable serialization expression");
+ if ("STATIC_CALL".equals(variableLiteral.getName())) {
+ return toStaticCallSerializationExpression(field, variableLiteral, serialzerArguments, tracer);
+ }
+ // All uppercase names are not fields, but utility methods.
+ else if (variableLiteral.getName().equals(variableLiteral.getName().toUpperCase())) {
+ return toUpperCaseSerializationExpression(field, variableLiteral, serialzerArguments, tracer);
+ } else if (isVariableLiteralImplicitField(variableLiteral)) { // If we are accessing implicit fields, we need to rely on a local variable instead.
+ tracer = tracer.dive("implicit field");
+ return tracer + toSerializationExpression(getReferencedImplicitField(variableLiteral), getReferencedImplicitField(variableLiteral).getSerializeExpression(), serialzerArguments);
+ } else if (isVariableLiteralVirtualField(variableLiteral)) {
+ tracer = tracer.dive("virtual field");
+ return tracer + "_value." + toVariableExpressionRest(variableLiteral);
+ }
+ // The synthetic checksumRawData is a local field and should not be accessed as bean property.
+ boolean isSerializerArg = "checksumRawData".equals(variableLiteral.getName()) || "_value".equals(variableLiteral.getName()) || "element".equals(variableLiteral.getName()) || "size".equals(variableLiteral.getName());
+ boolean isTypeArg = "_type".equals(variableLiteral.getName());
+ if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+ for (Argument serializerArgument : serialzerArguments) {
+ if (serializerArgument.getName().equals(variableLiteral.getName())) {
+ isSerializerArg = true;
+ break;
+ }
+ }
+ }
+ if (isSerializerArg) {
+ tracer = tracer.dive("serializer arg");
+ return tracer + variableLiteral.getName() + variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse("");
+ } else if (isTypeArg) {
+ tracer = tracer.dive("type arg");
+ String part = variableLiteral.getChild().map(VariableLiteral::getName).orElse("");
+ switch (part) {
+ case "name":
+ return tracer + "\"" + field.getTypeName() + "\"";
+ case "length":
+ return tracer + "\"" + ((SimpleTypeReference) field).getSizeInBits() + "\"";
+ case "encoding":
+ String encoding = ((StringTypeReference) field.getType()).getEncoding();
+ // Cut off the single quotes.
+ encoding = encoding.substring(1, encoding.length() - 1);
+ return tracer + "\"" + encoding + "\"";
+ default:
+ return tracer + "";
+ }
+ } else {
+ return tracer + "_value." + toVariableExpressionRest(variableLiteral);
+ }
+ }
+
+ private String toUpperCaseSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments, Tracer tracer) {
+ tracer = tracer.dive("UPPER_CASE");
+ StringBuilder sb = new StringBuilder(variableLiteral.getName());
+ if (variableLiteral.getArgs().isPresent()) {
+ sb.append("(");
+ boolean firstArg = true;
+ for (Term arg : variableLiteral.getArgs().get()) {
+ if (!firstArg) {
+ sb.append(", ");
+ }
+
+ if (arg instanceof VariableLiteral) {
+ VariableLiteral va = (VariableLiteral) arg;
+ boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName());
+ boolean isTypeArg = "_type".equals(va.getName());
+ if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+ for (Argument serializerArgument : serialzerArguments) {
+ if (serializerArgument.getName().equals(va.getName())) {
+ isSerializerArg = true;
+ break;
+ }
+ }
+ }
+ if (isSerializerArg) {
+ sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+ } else if (isTypeArg) {
+ String part = va.getChild().map(VariableLiteral::getName).orElse("");
+ switch (part) {
+ case "name":
+ sb.append("\"").append(field.getTypeName()).append("\"");
+ break;
+ case "length":
+ sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+ break;
+ case "encoding":
+ String encoding = ((StringTypeReference) field.getType()).getEncoding();
+ // Cut off the single quotes.
+ encoding = encoding.substring(1, encoding.length() - 1);
+ sb.append("\"").append(encoding).append("\"");
+ break;
+ }
+ } else {
+ sb.append(toVariableSerializationExpression(field, va, serialzerArguments));
+ }
+ } else if (arg instanceof StringLiteral) {
+ sb.append(((StringLiteral) arg).getValue());
+ }
+ firstArg = false;
+ }
+ sb.append(")");
+ }
+ return tracer + sb.toString();
+ }
+
+ private String toStaticCallSerializationExpression(TypedField field, VariableLiteral variableLiteral, List<Argument> serialzerArguments, Tracer tracer) {
+ tracer = tracer.dive("STATIC_CALL");
+ StringBuilder sb = new StringBuilder();
+ List<Term> arguments = variableLiteral.getArgs().orElseThrow(() -> new RuntimeException("A STATIC_CALL expression needs arguments"));
+ if (arguments.size() < 1) {
+ throw new RuntimeException("A STATIC_CALL expression expects at least one argument.");
+ }
+ // Get the class and method name
+ String methodName = arguments.get(0).asLiteral()
+ .orElseThrow(() -> new RuntimeException("First argument should be a literal"))
+ .asStringLiteral()
+ .orElseThrow(() -> new RuntimeException("Expecting the first argument of a 'STATIC_CALL' to be a StringLiteral")).
+ getValue();
+ methodName = methodName.substring(1, methodName.length() - 1);
+ sb.append(methodName).append("(");
+ for (int i = 1; i < arguments.size(); i++) {
+ Term arg = arguments.get(i);
+ if (i > 1) {
+ sb.append(", ");
+ }
+ if (arg instanceof VariableLiteral) {
+ VariableLiteral va = (VariableLiteral) arg;
+ // "readBuffer" and "_value" are always available in every parser.
+ boolean isSerializerArg = "readBuffer".equals(va.getName()) || "writeBuffer".equals(va.getName()) || "_value".equals(va.getName()) || "element".equals(va.getName());
+ boolean isTypeArg = "_type".equals(va.getName());
+ if (!isSerializerArg && !isTypeArg && serialzerArguments != null) {
+ for (Argument serializerArgument : serialzerArguments) {
+ if (serializerArgument.getName().equals(va.getName())) {
+ isSerializerArg = true;
+ break;
+ }
+ }
+ }
+ if (isSerializerArg) {
+ sb.append(va.getName()).append(va.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+ } else if (isTypeArg) {
+ String part = va.getChild().map(VariableLiteral::getName).orElse("");
+ switch (part) {
+ case "name":
+ sb.append("\"").append(field.getTypeName()).append("\"");
+ break;
+ case "length":
+ sb.append("\"").append(((SimpleTypeReference) field).getSizeInBits()).append("\"");
+ break;
+ case "encoding":
+ String encoding = ((StringTypeReference) field.getType()).getEncoding();
+ // Cut off the single quotes.
+ encoding = encoding.substring(1, encoding.length() - 1);
+ sb.append("\"").append(encoding).append("\"");
+ break;
+ }
+ } else {
+ sb.append(toVariableSerializationExpression(field, va, serialzerArguments));
+ }
+ } else if (arg instanceof StringLiteral) {
+ sb.append(((StringLiteral) arg).getValue());
+ }
+ }
+ sb.append(")");
+ return tracer + sb.toString();
+ }
+
+ private String toVariableExpressionRest(VariableLiteral variableLiteral) {
+ Tracer tracer = Tracer.start("variable expression rest");
+ // length is kind of a keyword in mspec, so we shouldn't be naming variables length. if we ask for the length of a object we can just return length().
+ // This way we can get the length of a string when serializing
+ String variableLiteralName = variableLiteral.getName();
+ if (variableLiteralName.equals("length")) {
+ tracer = tracer.dive("length");
+ return tracer + variableLiteralName + "()" + ((variableLiteral.isIndexed() ? "[" + variableLiteral.getIndex() + "]" : "") +
+ variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+ }
+ return tracer + "get" + WordUtils.capitalize(variableLiteralName) + "()" + ((variableLiteral.isIndexed() ? "[" + variableLiteral.getIndex() + "]" : "") +
+ variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(child)).orElse(""));
+ }
+
+ public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
+ int sizeInBits = 0;
+ StringBuilder sb = new StringBuilder();
+ for (Field field : complexTypeDefinition.getFields()) {
+ if (field instanceof ArrayField) {
+ ArrayField arrayField = (ArrayField) field;
+ final SimpleTypeReference type = (SimpleTypeReference) arrayField.getType();
+ switch (arrayField.getLoopType()) {
+ case COUNT:
+ sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), parserArguments)).append(" * ").append(type.getSizeInBits()).append(") + ");
+ break;
+ case LENGTH:
+ sb.append("(").append(toSerializationExpression(null, arrayField.getLoopExpression(), parserArguments)).append(" * 8) + ");
+ break;
+ case TERMINATED:
+ // No terminated.
+ break;
+ }
+ } else if (field instanceof TypedField) {
+ TypedField typedField = (TypedField) field;
+ final TypeReference type = typedField.getType();
+ if (field instanceof ManualField) {
+ ManualField manualField = (ManualField) field;
+ sb.append("(").append(toSerializationExpression(null, manualField.getLengthExpression(), parserArguments)).append(") + ");
+ } else if (type instanceof SimpleTypeReference) {
+ SimpleTypeReference simpleTypeReference = (SimpleTypeReference) type;
+ if (simpleTypeReference instanceof StringTypeReference) {
+ sb.append(toSerializationExpression(null, ((StringTypeReference) simpleTypeReference).getLengthExpression(), parserArguments)).append(" + ");
+ } else {
+ sizeInBits += simpleTypeReference.getSizeInBits();
+ }
+ } else {
+ // No ComplexTypeReference supported.
+ }
+ }
+ }
+ return sb.toString() + sizeInBits;
+ }
+
+ public String escapeValue(TypeReference typeReference, String valueString) {
+ if (valueString == null) {
+ return null;
+ }
+ if (typeReference instanceof SimpleTypeReference) {
+ SimpleTypeReference simpleTypeReference = (SimpleTypeReference) typeReference;
+ switch (simpleTypeReference.getBaseType()) {
+ case UINT:
+ case INT:
+ // If it's a one character string and is numeric, output it as char.
+ if (!NumberUtils.isParsable(valueString) && (valueString.length() == 1)) {
+ return "'" + valueString + "'";
+ }
+ break;
+ case STRING:
+ case VSTRING:
+ return "\"" + valueString + "\"";
+ }
+ }
+ return valueString;
+ }
+
+}
diff --git a/code-generation/language-java-ng/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput b/code-generation/language-java-ng/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
new file mode 100644
index 0000000..924bc01
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.language.LanguageOutput
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+org.apache.plc4x.language.java.JavaLanguageOutput
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/data-io-template.java.ftlh b/code-generation/language-java-ng/src/main/resources/templates/java/data-io-template.java.ftlh
new file mode 100644
index 0000000..25ebc58
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/resources/templates/java/data-io-template.java.ftlh
@@ -0,0 +1,425 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${type.name}IO.java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 ${helper.packageName(protocolName, languageName, outputFlavor)}.io;
+
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.spi.generation.EvaluationHelper;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WriteBufferByteBased;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
+import org.apache.plc4x.java.spi.values.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.time.*;
+import java.util.*;
+import java.util.function.Supplier;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
+public class ${type.name}IO {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
+ public static PlcValue staticParse(ReadBuffer readBuffer<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+ <#assign defaultCaseOutput=false>
+ <#assign dataIoTypeDefinition=type.asDataIoTypeDefinition().orElseThrow()>
+ <#list dataIoTypeDefinition.switchField.cases as case>
+ <#if case.discriminatorValues?has_content>
+ <@compress single_line=true>
+ if(
+ <#list case.discriminatorValues as discriminatorValue>
+ <#assign discriminatorExpression=dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValue?index]>
+ EvaluationHelper.equals(
+ ${helper.toParseExpression(null, discriminatorExpression, parserArguments)}
+ ,
+ <#if helper.discriminatorValueNeedsStringEqualityCheck(discriminatorExpression)>
+ "${discriminatorValue}"
+ <#elseif helper.isComplexTypeReference(parserArguments[discriminatorValue?index].type)>
+ <#if helper.isEnumTypeReference(parserArguments[discriminatorValue?index].type)>
+ ${helper.getLanguageTypeNameForTypeReference(parserArguments[discriminatorValue?index].type, false)}
+ .
+ ${discriminatorValue}
+ <#else>
+ ${discriminatorValue}
+ </#if>
+ <#else>
+ ${discriminatorValue}
+ </#if>
+ )
+ <#sep> && </#sep>
+ </#list>
+ )
+ </...@compress>
+ <#else>
+ <#assign defaultCaseOutput=true>
+ </#if>{ // ${case.name}
+ <#assign valueDefined=false>
+ <#list case.fields as field>
+ <#switch field.typeName>
+ <#case "array">
+ <#assign arrayField=field.asArrayField().orElseThrow()>
+ // Array field (${arrayField.name})
+ <#-- Only update curPos if the length expression uses it -->
+ <#if arrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ <#-- If this is a count array, we can directly initialize an array with the given size -->
+ <#if field.isCountArrayField()>
+ // Count array
+ if(${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)} > Integer.MAX_VALUE) {
+ throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+ }
+ List<PlcValue> ${arrayField.name};
+ {
+ int itemCount = (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)};
+ ${arrayField.name} = new LinkedList<>();
+ for(int curItem = 0; curItem < itemCount; curItem++) {
+ ${arrayField.name}.add(new ${helper.getPlcValueTypeForTypeReference(arrayField.type)}((${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}) <#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)})<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if field.params.isPresent()>, <#list arrayField.params.orElseThrow [...]
+ }
+ }
+ <#-- In all other cases do we have to work with a list, that is later converted to an array -->
+ <#else>
+ <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
+ <#if arrayField.isLengthArrayField()>
+ // Length array
+ long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)};
+ long ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
+ List<PlcValue> value = new LinkedList<>();
+ while(readBuffer.getPos() < ${arrayField.name}EndPos) {
+ value.add(
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ new ${helper.getPlcValueTypeForTypeReference(arrayField.type)}(${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)})
+ <#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+ <#if arrayField.params.isPresent()>,
+ <#list arrayField.params.orElseThrow() as parserArgument>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument,parserArguments)})
+ <#sep>, </#sep>
+ </#list>
+ </#if>
+ )
+ </#if>
+ );
+ }
+ <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
+ <#elseif arrayField.isTerminatedArrayField()>
+ // Terminated array
+ List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> ${arrayField.name} = new LinkedList<>();
+ while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression,parserArguments)}))) {
+ ${arrayField.name}.add(<#if helper.isSimpleTypeReference(arrayField.type)>${helper.getReadBufferReadMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}<#else>${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index [...]
+
+ <#-- After parsing, update the current position, but only if it's needed -->
+ <#if arrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ }
+ </#if>
+ </#if>
+ <#if arrayField.name == "value">
+ <#assign valueDefined=true>
+ </#if>
+ <#break>
+ <#case "const">
+ <#assign constField=field.asConstField().orElseThrow()>
+
+ // Const Field (${constField.name})
+ ${helper.getNonPrimitiveLanguageTypeNameForField(constField)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), "", constField)};
+ if(${constField.name} != ${dataIoTypeDefinition.name}.${constField.name?upper_case}) {
+ throw new ParseException("Expected constant value " + ${dataIoTypeDefinition.name}.${constField.name?upper_case} + " but got " + ${constField.name});
+ }
+ <#if constField.name == "value">
+ <#assign valueDefined=true>
+ </#if>
+ <#break>
+ <#case "enum">
+ <#assign enumField=field.asEnumField().orElseThrow()>
+
+ // Enum field (${enumField.name})
+ ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)} ${enumField.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type.asSimpleTypeReference().orElseThrow()), "", enumField)});
+ <#if enumField.name == "value">
+ <#assign valueDefined=true>
+ </#if>
+ <#break>
+ <#case "manual">
+ <#assign manualField=field.asManualField().orElseThrow()>
+
+ // Manual Field (${manualField.name})
+ ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.parseExpression,parserArguments)});
+ <#if manualField.name == "value">
+ <#assign valueDefined=true>
+ </#if>
+ <#break>
+ <#case "reserved">
+ <#assign reservedField=field.asReservedField().orElseThrow()>
+
+ // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+ {
+ ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), "", reservedField)};
+ if(reserved != ${helper.getReservedValue(reservedField)}) {
+ LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field.");
+ }
+ }
+ <#break>
+ <#case "simple">
+ <#assign simpleField=field.asSimpleField().orElseThrow()>
+
+ <#if helper.isEnumField(simpleField)>
+ // Enum field (${simpleField.name})
+ ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} ${simpleField.name} = ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)});
+ <#else>
+ // Simple Field (${simpleField.name})
+ ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} ${simpleField.name} = <#if helper.isSimpleTypeReference(simpleField.type)>${helper.getReadBufferReadMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}<#else>${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if simpleField.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(he [...]
+ </#if>
+ <#if case.name == "Struct" ||
+ ((case.name == "DATE_AND_TIME") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day") || (simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
+ ((case.name == "DATE_AND_TIME") && (simpleField.name == "secondsSinceEpoch")) ||
+ ((case.name == "DATE") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day"))) ||
+ ((case.name == "TIME_OF_DAY") && ((simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
+ simpleField.name == "value">
+ <#assign valueDefined=true>
+ </#if>
+ <#break>
+ </#switch>
+ </#list>
+ <#if case.name == "Struct">
+
+ <#-- In this case we need to wrap each field in a PlcValue that matches it's natural type -->
+ Map<String, PlcValue> _map = new HashMap<>();
+ <#list case.fields as field>
+ <#if field.isArrayField()>
+ <#assign field=field.asArrayField().orElseThrow()>
+ _map.put("${field.name}", new PlcList(${field.name}));
+ <#elseif field.isPropertyField()>
+ <#assign field=field.asPropertyField().orElseThrow()>
+ <#switch helper.getLanguageTypeNameForTypeReference(field.type)>
+ <#case "Boolean">
+ _map.put("${field.name}", new PlcBOOL(${field.name}));
+ <#break>
+ <#case "Byte">
+ _map.put("${field.name}", new PlcSINT(${field.name}));
+ <#break>
+ <#case "Short">
+ _map.put("${field.name}", new PlcINT(${field.name}));
+ <#break>
+ <#case "Integer">
+ _map.put("${field.name}", new PlcDINT(${field.name}));
+ <#break>
+ <#case "Long">
+ _map.put("${field.name}", new PlcLINT(${field.name}));
+ <#break>
+ <#case "BigInteger">
+ _map.put("${field.name}", new PlcBigInteger(${field.name}));
+ <#break>
+ <#case "Float">
+ _map.put("${field.name}", new PlcREAL(${field.name}));
+ <#break>
+ <#case "Double">
+ _map.put("${field.name}", new PlcLREAL(${field.name}));
+ <#break>
+ <#case "BigDecimal">
+ _map.put("${field.name}", new PlcBigDecimal(${field.name}));
+ <#break>
+ <#case "String">
+ _map.put("${field.name}", new PlcSTRING(${field.name}));
+ <#break>
+ <#case "LocalTime">
+ _map.put("${field.name}", new PlcTIME_OF_DAY(${field.name}));
+ <#break>
+ <#case "LocalDate">
+ _map.put("${field.name}", new PlcDATE(${field.name}));
+ <#break>
+ <#case "LocalDateTime">
+ _map.put("${field.name}", new PlcDATE_AND_TIME(${field.name}));
+ <#break>
+ </#switch>
+ </#if>
+ </#list>
+ <#assign valueDefined=true>
+ </#if>
+
+ <#if valueDefined>
+ <#switch case.name>
+ <#case "TIME">
+ return new PlcTIME(value);
+ <#break>
+ <#case "DATE">
+ <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day")>
+ LocalDate value = LocalDate.of(year.intValue(), (month == 0) ? 1 : month.intValue(), (day == 0) ? 1 : day.intValue());
+ </#if>
+ return new PlcDATE(value);
+ <#break>
+ <#case "TIME_OF_DAY">
+ <#if helper.hasFieldsWithNames(case.fields, "hour", "minutes", "seconds", "nanos")>
+ LocalTime value = LocalTime.of(hour.intValue(), minutes.intValue(), seconds.intValue(), nanos.intValue());
+ <#elseif helper.hasFieldsWithNames(case.fields, "hour", "minutes", "seconds")>
+ LocalTime value = LocalTime.of(hour.intValue(), minutes.intValue(), seconds.intValue());
+ </#if>
+ return new PlcTIME_OF_DAY(value);
+ <#break>
+ <#case "DATE_AND_TIME">
+ <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds", "nanos")>
+ LocalDateTime value = LocalDateTime.of(year.intValue(), (month == 0) ? 1 : month.intValue(), (day == 0) ? 1 : day.intValue(), hour.intValue(), minutes.intValue(), seconds.intValue(), nanos.intValue());
+ <#elseif helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds")>
+ LocalDateTime value = LocalDateTime.of(year.intValue(), (month == 0) ? 1 : month.intValue(), (day == 0) ? 1 : day.intValue(), hour.intValue(), minutes.intValue(), seconds.intValue());
+ <#elseif helper.hasFieldsWithNames(case.fields, "secondsSinceEpoch")>
+ LocalDateTime value = LocalDateTime.ofEpochSecond(secondsSinceEpoch, 0, ZoneOffset.UTC);
+ </#if>
+ return new PlcDATE_AND_TIME(value);
+ <#break>
+ <#case "Struct">
+ return new PlcStruct(_map);
+ <#break>
+ <#case "List">
+ return new PlcList(value);
+ <#break>
+ <#default>
+ return new Plc${case.name}(value);
+ </#switch>
+ </#if>
+ }<#sep> else </#sep></#list>
+ <#if !defaultCaseOutput>
+ return null;
+ </#if>
+ }
+
+<#if outputFlavor != "passive">
+ public static WriteBufferByteBased staticSerialize(PlcValue _value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+ return staticSerialize(_value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>, ByteOrder.BIG_ENDIAN);
+ }
+
+ public static WriteBufferByteBased staticSerialize(PlcValue _value<#if type.parserArguments.isPresent()>, <#list type.parserArguments.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>, ByteOrder byteOrder) throws ParseException {
+ <#assign defaultCaseOutput=false>
+ <#assign dataIoTypeDefinition=type.asDataIoTypeDefinition().orElseThrow()>
+ <#list dataIoTypeDefinition.switchField.cases as case><#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments.orElseThrow())},<#if helper.discriminatorValueNeedsStringEqualityCheck(dataIoTypeDefinition.switchField.discriminatorExpressions[discriminatorValue?index])>"${discrimin [...]
+ WriteBufferByteBased writeBuffer = new WriteBufferByteBased((int) Math.ceil(((float) ${helper.getSizeInBits(case,parserArguments)}) / 8.0f), byteOrder);
+
+ <#list case.fields as field>
+ <#switch field.typeName>
+ <#case "array">
+ <#assign arrayField=field.asArrayField().orElseThrow()>
+ PlcList values = (PlcList) _value;
+
+ <#if case.name == "Struct">
+ for (PlcValue val : ((List<PlcValue>) values.getStruct().get("${arrayField.name}").getList())) {
+ ${helper.getLanguageTypeNameForField(arrayField)} value = (${helper.getLanguageTypeNameForField(arrayField)}) val.get${helper.getLanguageTypeNameForField(arrayField)?cap_first}();
+ ${helper.getWriteBufferWriteMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "value", arrayField)};
+ }
+ <#else>
+ for (PlcValue val : ((List<PlcValue>) values.getList())) {
+ ${helper.getLanguageTypeNameForField(arrayField)} value = (${helper.getLanguageTypeNameForField(arrayField)}) val.get${helper.getLanguageTypeNameForField(arrayField)?cap_first}();
+ ${helper.getWriteBufferWriteMethodCall(arrayField.type.asSimpleTypeReference().orElseThrow(), "(" + arrayField.name + ")", arrayField)};
+ }
+ </#if>
+
+ <#if case.name == "BOOL">
+ while (writeBuffer.getPos() < writeBuffer.getData().length) {
+ writeBuffer.writeBit(false);
+ }
+ </#if>
+ <#break>
+ <#case "const">
+ <#assign constField=field.asConstField().orElseThrow()>
+ // Const Field (${constField.name})
+ ${helper.getWriteBufferWriteMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), constField.referenceValue, constField)};
+ <#break>
+ <#case "enum">
+ <#assign enumField=field.asEnumField().orElseThrow()>
+ // Enum field (${enumField.name})
+ ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${enumField.name?cap_first}();
+ ${helper.getWriteBufferWriteMethodCall(helper.getEnumBaseTypeReference(field.asTypedField().orElseThrow().type), "(" + enumField.name + ".getValue())", enumField)};
+ <#break>
+ <#case "manual">
+ <#assign manualField=field.asManualField().orElseThrow()>
+ // Manual Field (${manualField.name})
+ ${helper.toSerializationExpression(manualField, manualField.serializeExpression, type.parserArguments.orElse(null))};
+ <#break>
+ <#case "reserved">
+ <#assign reservedField=field.asReservedField().orElseThrow()>
+ // Reserved Field
+ ${helper.getWriteBufferWriteMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), helper.getReservedValue(reservedField), reservedField)};
+ <#break>
+ <#case "simple">
+ <#assign simpleField=field.asSimpleField().orElseThrow()>
+ // Simple Field (${simpleField.name})
+ <#if case.name == "Struct">
+ ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.getStruct().get("${simpleField.name}").get${helper.getLanguageTypeNameForField(simpleField)?cap_first}();
+ <#else>
+ <#if simpleField.name == "value">
+ ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${helper.getLanguageTypeNameForField(simpleField)?cap_first}();
+ <#else>
+ <#-- Just for now -->
+ ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = ${helper.getNullValueForTypeReference(simpleField.type)};
+ </#if>
+ </#if>
+ <#if helper.isSimpleTypeReference(simpleField.type)>
+ ${helper.getWriteBufferWriteMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "(" + simpleField.name + ")", simpleField)};
+ <#else>
+ ${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.staticSerialize(writeBuffer, ${simpleField.name});
+ </#if>
+ <#break>
+ </#switch>
+ </#list>
+ return writeBuffer;
+ }<#sep> else </#sep></#list>
+ <#if !defaultCaseOutput>
+ return null;
+ </#if>
+ }
+</#if>
+
+}
+</#outputformat>
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/enum-package-info-template.java.ftlh b/code-generation/language-java-ng/src/main/resources/templates/java/enum-package-info-template.java.ftlh
new file mode 100644
index 0000000..8c79f5b
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/resources/templates/java/enum-package-info-template.java.ftlh
@@ -0,0 +1,50 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/types/package-info.java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// Code generated by code-generation. DO NOT EDIT.
+
+package ${helper.packageName(protocolName, languageName, outputFlavor)}.types;
+</#outputformat>
\ No newline at end of file
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/enum-template.java.ftlh b/code-generation/language-java-ng/src/main/resources/templates/java/enum-template.java.ftlh
new file mode 100644
index 0000000..321932f
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/resources/templates/java/enum-template.java.ftlh
@@ -0,0 +1,144 @@
+<#--
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/types/${type.name}.java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 ${helper.packageName(protocolName, languageName, outputFlavor)}.types;
+
+import org.apache.plc4x.java.spi.generation.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+public enum ${type.name} {
+
+<#list type.enumValues as enumValue>
+ ${enumValue.name}(<#if type.type?has_content>(${helper.getLanguageTypeNameForTypeReference(type.type, true)}) <#if type.type.isStringTypeReference()>"${enumValue.value}"<#elseif helper.isComplexTypeReference(type.type)><#if helper.isEnumTypeReference(type.type)>${helper.getLanguageTypeNameForTypeReference(type.type, true)}.${enumValue.value}<#else>${enumValue.value}</#if><#else>${enumValue.value}</#if></#if><#if type.constantNames?has_content><#if type.type?has_content>, </#if><#list [...]
+</#sep></#list>;
+
+<#if type.type?has_content>
+ private static final Logger logger = LoggerFactory.getLogger(${type.name}.class);
+
+ private static final Map<${helper.getLanguageTypeNameForTypeReference(type.type, false)}, ${type.name}> map;
+ static {
+ map = new HashMap<>();
+ for (${type.name} value : ${type.name}.values()) {
+ map.put((${helper.getLanguageTypeNameForTypeReference(type.type, true)}) value.getValue(), value);
+ }
+ }
+
+ private ${helper.getLanguageTypeNameForTypeReference(type.type, true)} value;
+</#if>
+<#if type.constantNames?has_content>
+ <#list type.constantNames as constantName>
+ private ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} ${constantName};
+ </#list>
+</#if>
+
+ ${type.name}(<#if type.type?has_content>${helper.getLanguageTypeNameForTypeReference(type.type, true)} value</#if><#if type.constantNames?has_content><#if type.type?has_content>, </#if><#list type.constantNames as constantName>${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} ${constantName}<#sep>, </#sep></#list></#if>) {
+<#if type.type?has_content> this.value = value;</#if>
+<#if type.constantNames?has_content>
+ <#list type.constantNames as constantName>
+ this.${constantName} = ${constantName};
+ </#list>
+</#if>
+ }
+
+<#if type.type?has_content>
+ public ${helper.getLanguageTypeNameForTypeReference(type.type, true)} getValue() {
+ return value;
+ }
+</#if>
+
+<#if type.constantNames?has_content>
+ <#list type.constantNames as constantName>
+ public ${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} get${constantName?cap_first}() {
+ return ${constantName};
+ }
+
+ public static ${type.name} firstEnumForField${constantName?cap_first}(${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} fieldValue) {
+ for (${type.name} _val : ${type.name}.values()) {
+ if(_val.get${constantName?cap_first}() == fieldValue) {
+ return _val;
+ }
+ }
+ return null;
+ }
+
+ public static List<${type.name}> enumsForField${constantName?cap_first}(${helper.getLanguageTypeNameForTypeReference(type.getConstantType(constantName), true)} fieldValue) {
+ List<${type.name}> _values = new ArrayList();
+ for (${type.name} _val : ${type.name}.values()) {
+ if(_val.get${constantName?cap_first}() == fieldValue) {
+ _values.add(_val);
+ }
+ }
+ return _values;
+ }
+
+ </#list>
+</#if>
+<#if type.type?has_content>
+ public static ${type.name} enumForValue(${helper.getLanguageTypeNameForTypeReference(type.type, true)} value) {
+ if (!map.containsKey(value)) {
+ logger.error("No ${type.name} for value {}", value);
+ }
+ return map.get(value);
+ }
+</#if>
+
+<#if type.type?has_content>
+ public static Boolean isDefined(${helper.getLanguageTypeNameForTypeReference(type.type, true)} value) {
+ return map.containsKey(value);
+ }
+</#if>
+
+}
+</#outputformat>
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java-ng/src/main/resources/templates/java/io-template.java.ftlh
new file mode 100644
index 0000000..ac31675
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/resources/templates/java/io-template.java.ftlh
@@ -0,0 +1,936 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${type.name}IO.java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 ${helper.packageName(protocolName, languageName, outputFlavor)}.io;
+
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.*;
+<#if helper.getComplexTypeReferences()?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if>
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.api.value.PlcValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.time.*;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Supplier;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
+public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<${type.name}, ${type.name}><#else>MessageInput<${type.name}></#if> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class);
+
+<#-- The parse and serialize methods here are just proxies for forwardning the requests to static counterparts -->
+<#if !type.isDiscriminatedChildTypeDefinition()>
+ @Override
+ public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
+ <#if parserArguments?has_content>
+ if((args == null) || (args.length != ${parserArguments?size})) {
+ throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
+ }
+ <#list parserArguments as parserArgument>
+ ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name};
+ if(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) {
+ ${parserArgument.name} = (${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) args[${parserArgument?index}];
+ <#if helper.isSimpleTypeReference(parserArgument.type)>
+ } else if (args[${parserArgument?index}] instanceof String) {
+ ${parserArgument.name} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}.valueOf((String) args[${parserArgument?index}]);
+ </#if>
+ } else {
+ throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName());
+ }
+ </#list>
+ </#if>
+ return ${type.name}IO.staticParse(readBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+ }
+
+ <#if outputFlavor != "passive">
+ @Override
+ public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException {
+ <#if helper.getSerializerArguments(parserArguments)?has_content>
+ if((args == null) || (args.length != ${parserArguments?size})) {
+ throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
+ }
+ <#list helper.getSerializerArguments(parserArguments) as serializerArgument>
+ if(!(args[${serializerArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)})) {
+ throw new PlcRuntimeException("Argument ${serializerArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} but was " + args[${serializerArgument?index}].getClass().getName());
+ }
+ ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)}) args[${serializerArgument?index}];
+ </#list>
+ </#if>
+ ${type.name}IO.staticSerialize(writeBuffer, value<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+ }
+
+ </#if>
+<#else>
+ @Override
+ public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException {
+ return (${type.name}) new ${type.parentType.name}IO().parse(readBuffer, args);
+ }
+
+<#if outputFlavor != "passive">
+ @Override
+ public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException {
+ new ${type.parentType.name}IO().serialize(writeBuffer, value, args);
+ }
+
+</#if>
+</#if>
+<#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing -->
+ <#assign hasParserArguments=parserArguments?has_content/>
+ <#assign parserArgumentList><#if hasParserArguments><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ <#assign hasParentParserArguments=(type.parentType?? && type.parentType.parserArguments.isPresent() && type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments)?has_content)>
+ <#assign parentParserArgumentList><#if hasParentParserArguments><#list type.parentType.parserArguments.orElseThrow()?filter(arg -> hasParserArguments && !parserArguments?map(argument->argument.name)?seq_contains(arg.name) || !hasParserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ public static ${type.name}<#if type.isDiscriminatedChildTypeDefinition()>Builder</#if> staticParse(ReadBuffer readBuffer<#if hasParserArguments>, ${parserArgumentList}</#if><#if hasParentParserArguments>, ${parentParserArgumentList}</#if>) throws ParseException {
+ readBuffer.pullContext("${type.name}");
+ int startPos = readBuffer.getPos();
+ int curPos;
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "array">
+ <#assign arrayField = field.asArrayField().orElseThrow()>
+ <#if arrayField.type.isByteBased()>
+ // Byte Array field (${arrayField.name})
+ <#assign numberOfBytesExpression>
+ <#compress>
+ <#if field.isCountArrayField()>
+ int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
+ <#elseif field.isLengthArrayField()>
+ int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
+ <#elseif field.isTerminatedArrayField()>
+ <#-- TODO: we need to find out to implement this-->
+ int numberOfBytes := ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
+ <#else>
+ <#-- TODO: we should throw a exception here-->
+ int numberOfBytes := -1
+ </#if>
+ </#compress>
+ </#assign>
+ ${numberOfBytesExpression}
+ byte[] ${arrayField.name} = readBuffer.readByteArray("${arrayField.name}", numberOfBytes);
+ <#else>
+ // Array field (${arrayField.name})
+ readBuffer.pullContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ <#-- Only update curPos if the length expression uses it -->
+ <#if arrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ <#-- If this is a count array, we can directly initialize an array with the given size -->
+ <#if field.isCountArrayField()>
+ // Count array
+ if(${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)} > Integer.MAX_VALUE) {
+ throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+ }
+ ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name};
+ {
+ int itemCount = Math.max(0, (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
+ ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
+ for(int curItem = 0; curItem < itemCount; curItem++) {
+ <#-- When parsing simple types, there is nothing that could require the "lastItem" -->
+ <#if !helper.isSimpleTypeReference(arrayField.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
+ <@compress single_line=true>
+ ${arrayField.name}[curItem] =
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
+ <#else>
+ ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+ <#if field.params.isPresent()>
+ ,
+ <#list field.params.orElseThrow() as parserArgument>
+ <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true) = 'String'>
+ ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
+ <#else>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
+ </#if>
+ </#list>
+ </#if>
+ <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
+ <#-- We expose the parentParserArguments to the child here too-->
+ <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
+ <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
+ )
+ <#if helper.getTypeDefinitionForTypeReference(arrayField.type).isDiscriminatedChildTypeDefinition()>
+ .build()
+ </#if>
+ </#if>;
+ </...@compress>
+ }
+ }
+ <#-- In all other cases do we have to work with a list, that is later converted to an array -->
+ <#else>
+ <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
+ <#if field.isLengthArrayField()>
+ // Length array
+ long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
+ List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
+ long ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
+ while(readBuffer.getPos() < ${arrayField.name}EndPos) {
+ <@compress single_line=true>
+ _${arrayField.name}List.add(
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
+ <#else>
+ ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+ <#if field.params.isPresent()>
+ ,
+ <#list field.params.orElseThrow() as parserArgument>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
+ (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
+ </#list>
+ </#if>
+ <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
+ <#-- We expose the parentParserArguments to the child here too-->
+ <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
+ <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
+ )
+ </#if>
+ );
+ </...@compress>
+ <#-- After parsing, update the current position, but only if it's needed -->
+ <#if arrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ }
+ <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
+ <#elseif field.isTerminatedArrayField()>
+ // Terminated array
+ List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
+ while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}))) {
+ <@compress single_line=true>
+ _${arrayField.name}List.add(
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ ${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
+ <#else>
+ ${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+ <#if field.params.isPresent()>
+ ,
+ <#list field.params.orElseThrow() as parserArgument>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
+ (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
+ </#list>
+ </#if>
+ <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
+ <#-- We expose the parentParserArguments to the child here too-->
+ <#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
+ <#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ <#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
+ )
+ </#if>
+ );
+ </...@compress>
+
+ <#-- After parsing, update the current position, but only if it's needed -->
+ <#if arrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ }
+ </#if>
+ <#--
+ Convert the list into an array. However if the array is of a primitive
+ type we have to iterate over it's elements and explicitly cast them.
+ Otherwise a simple toArray call is fine.
+ -->
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${arrayField.name}List.size()];
+ for(int i = 0; i < _${arrayField.name}List.size(); i++) {
+ ${arrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${arrayField.name}List.get(i);
+ }
+ <#else>
+ ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]);
+ </#if>
+ </#if>
+ readBuffer.closeContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ </#if>
+ <#break>
+ <#case "checksum">
+ <#assign checksumField = field.asChecksumField().orElseThrow()>
+ <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Checksum Field (checksum)
+ {
+ ${helper.getLanguageTypeNameForField(field)} checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
+ ${helper.getLanguageTypeNameForField(field)} checksumRef = ${helper.getReadBufferReadMethodCall("checksum", simpleTypeReference, "", checksumField)};
+ checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, parserArguments)});
+ if(checksum != checksumRef) {
+ throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X", checksumRef & 0xFFFF, checksum & 0xFFFF));
+ }
+ }
+ <#break>
+ <#case "const">
+ <#assign constField = field.asConstField().orElseThrow()>
+
+ // Const Field (${constField.name})
+ <#if helper.isSimpleTypeReference(constField.type)>
+ <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
+ ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.name, simpleTypeReference, "", constField)};
+ <#else>
+ ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(constField.name, helper.getEnumBaseTypeReference(constField.type), "", constField)});
+ </#if>
+ if(${constField.name} != ${type.name}.${constField.name?upper_case}) {
+ throw new ParseException("Expected constant value " + ${type.name}.${constField.name?upper_case} + " but got " + ${constField.name});
+ }
+ <#break>
+ <#case "discriminator">
+ <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
+
+ // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
+ <#if helper.isEnumField(field)>
+ ${helper.getLanguageTypeNameForField(discriminatorField)} ${discriminatorField.name} = ${helper.getLanguageTypeNameForField(discriminatorField)}.enumForValue(${helper.getReadBufferReadMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "", discriminatorField)});
+ <#else>
+ <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
+ <@compress single_line=true>
+ ${helper.getLanguageTypeNameForField(discriminatorField)} ${discriminatorField.name} =
+ <#if helper.isSimpleTypeReference(discriminatorField.type)>
+ ${helper.getReadBufferReadMethodCall(discriminatorField.name, simpleTypeReference, "", discriminatorField)}
+ <#else>
+ ${discriminatorField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
+ <#if discriminatorField.params.isPresent()>
+ ,
+ <#list discriminatorField.params.orElseThrow() as parserArgument>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
+ (${helper.toParseExpression(discriminatorField, parserArgument, null)})<#sep>, </#sep>
+ </#list>
+ </#if>
+ )
+ </#if>;
+ </...@compress>
+ </#if>
+
+ <#break>
+ <#case "enum">
+ <#assign enumField = field.asEnumField().orElseThrow()>
+
+ readBuffer.pullContext("${enumField.name}");
+ // Enum field (${enumField.name})
+ <#if enumField.fieldName.isPresent()>
+ ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.firstEnumForField${enumField.fieldName.orElseThrow()?cap_first}(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
+ <#else>
+ ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)});
+ </#if>
+ readBuffer.closeContext("${enumField.name}");
+ <#break>
+ <#case "implicit">
+ <#assign implicitField = field.asImplicitField().orElseThrow()>
+ <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
+ ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = ${helper.getReadBufferReadMethodCall(implicitField.name, simpleTypeReference, "", implicitField)};
+ <#break>
+ <#case "manualArray">
+ <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
+
+ readBuffer.pullContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ // Manual Array Field (${manualArrayField.name})
+ <#-- Only update curPos if the length expression uses it -->
+ <#if manualArrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ <#-- If this is a count array, we can directly initialize an array with the given size -->
+ <#if field.isCountArrayField()>
+ // Count array
+ int _${manualArrayField.name}Count = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)};
+ ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}Count];
+ for(int i = 0; i < _${manualArrayField.name}Count; i++) {
+ ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)});
+ }
+ <#-- In all other cases do we have to work with a list, that is later converted to an array -->
+ <#else>
+ <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
+ <#if field.isLengthArrayField()>
+ // Length array
+ long _${manualArrayField.name}Length = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)};
+ List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
+ long ${manualArrayField.name}EndPos = readBuffer.getPos() + _${manualArrayField.name}Length;
+ while(readBuffer.getPos() < ${manualArrayField.name}EndPos) {
+ _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)}));
+ <#-- After parsing, update the current position, but only if it's needed -->
+ <#if manualArrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ }
+ <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
+ <#elseif field.isTerminatedArrayField()>
+ // Terminated array
+ List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>();
+ while(!((boolean) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, parserArguments)}))) {
+ _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, parserArguments)}));
+
+ <#-- After parsing, update the current position, but only if it's needed -->
+ <#if manualArrayField.loopExpression.contains("curPos")>
+ curPos = readBuffer.getPos() - startPos;
+ </#if>
+ }
+ </#if>
+ <#--
+ Convert the list into an array. However if the array is of a primitive
+ type we have to iterate over it's elements and explicitly cast them.
+ Otherwise a simple toArray call is fine.
+ -->
+ <#if helper.isSimpleTypeReference(field.type)>
+ ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}List.size()];
+ for(int i = 0; i < _${manualArrayField.name}List.size(); i++) {
+ ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${manualArrayField.name}List.get(i);
+ }
+ <#else>
+ ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = _${manualArrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}[0]);
+ </#if>
+ </#if>
+ readBuffer.closeContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ <#break>
+ <#case "manual">
+ <#assign manualField = field.asManualField().orElseThrow()>
+
+ // Manual Field (${manualField.name})
+ ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, parserArguments)});
+ <#break>
+ <#case "optional">
+ <#assign optionalField = field.asOptionalField().orElseThrow()>
+
+ // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false)
+ ${helper.getLanguageTypeNameForField(optionalField)} ${optionalField.name} = null;
+ <#-- TODO: we need to initalize base types-->
+ curPos = readBuffer.getPos();
+ try {
+ <#if optionalField.conditionExpression.present && optionalField.conditionExpression.orElseThrow().contains("curPos")>
+ curPos = readBuffer.getPos();
+ </#if>
+ <#if optionalField.conditionExpression.present>
+ if(${helper.toParseExpression(optionalField, optionalField.conditionExpression.get(), parserArguments)}) {
+ </#if>
+ <@compress single_line=true>
+ ${optionalField.name} =
+ <#if helper.isEnumField(optionalField)>
+ ${helper.getLanguageTypeNameForField(optionalField)}.enumForValue(
+ ${helper.getReadBufferReadMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "", optionalField)}
+ )
+ <#elseif helper.isComplexTypeReference(optionalField.type)>
+ <#assign complexTypeReference=optionalField.type.asComplexTypeReference().orElseThrow()>
+ <#assign typeName=complexTypeReference.name>
+ <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
+ <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
+ <#-- Usually you don't use child directly unless they are parameterized #-->
+ <#assign typeName=typeDefinition.parentType.name>
+ <#assign typeDefinition=typeDefinition.parentType>
+ </#if>
+ <#-- We downcast to the referenced type-->
+ (${complexTypeReference.name}) ${typeName}IO.staticParse(
+ readBuffer
+ <#if field.params.isPresent()>,
+ <#list field.params.orElseThrow() as parserArgument>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(optionalField.type, parserArgument?index), true)})
+ (${helper.toParseExpression(optionalField, parserArgument, parserArguments)})<#sep>, </#sep>
+ </#list>
+ </#if>
+ <#if complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
+ <#assign argumentOffset=0>
+ <#if field.params.isPresent()><#assign argumentOffset=field.params.orElseThrow()?size></#if>
+ ,
+ <#list complexTypeReference.params.orElseThrow() as typeParam>
+ <#-- We cast here explicitly as java sometimes can't infer the type. e.g. 0 is a int and not a byte#-->
+ (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments.orElseThrow()[typeParam?index + argumentOffset].type, true)})
+ ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
+ </#list>
+ </#if>
+ )
+ <#else>
+ ${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type.asSimpleTypeReference().orElseThrow(), "", optionalField)}
+ </#if>
+ ;
+ </...@compress>
+
+ <#if optionalField.conditionExpression.present>
+ }
+ </#if>
+ } catch(ParseAssertException ignore){
+ readBuffer.reset(curPos);
+ }
+ <#break>
+ <#case "assert">
+ <#assign assertField = field.asAssertField().orElseThrow()>
+
+ // Assert Field
+ <#if helper.isEnumField(assertField)>
+ ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getLanguageTypeNameForField(assertField)}.enumForValue(${helper.getReadBufferReadMethodCall(assertField.name, helper.getEnumBaseTypeReference(simpleTypeReference), "", assertField)});
+ <#elseif helper.isComplexTypeReference(assertField.type)>
+ <#assign complexTypeReference=assertField.type.asComplexTypeReference().orElseThrow()>
+ <#assign typeName=complexTypeReference.name>
+ <#assign typeDefinition=helper.getTypeDefinitionForTypeReference(complexTypeReference)>
+ <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
+ <#assign typeName=typeDefinition.getParentType().name>
+ </#if>
+ <@compress single_line=true>
+ ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = (${complexTypeReference.name}) ${typeName}IO.staticParse(readBuffer
+ <#if field.params.isPresent()>
+ ,
+ <#list field.params.orElseThrow() as parserArgument>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleTypeReference, parserArgument?index), true)})
+ (${helper.toParseExpression(assertField, parserArgument, parserArguments)})<#sep>, </#sep>
+ </#list>
+ </#if>
+ <#if complexTypeReference.params.isPresent()>
+ ,
+ <#list complexTypeReference.params.orElseThrow() as typeParam>
+ ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
+ </#list>
+ </#if>);
+ </...@compress>
+ <#else>
+ <#assign simpleTypeReference = assertField.type.asSimpleTypeReference().orElseThrow()>
+ ${helper.getLanguageTypeNameForField(field)} ${assertField.name} = ${helper.getReadBufferReadMethodCall(assertField.name, simpleTypeReference.asSimpleTypeReference().orElseThrow(), "", assertField)};
+ </#if>
+ if(${assertField.name} != ${helper.toParseExpression(assertField.asTypedField().orElseThrow(), assertField.conditionExpression, parserArguments)}) {
+ throw new ParseAssertException("assertField ${assertField.name} with value " + ${assertField.name} + " didn't match the expected value " + ${helper.toParseExpression(assertField, assertField.conditionExpression, parserArguments)});
+ }
+ <#break>
+ <#case "padding">
+ <#assign paddingField = field.asPaddingField().orElseThrow()>
+ <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Padding Field (padding)
+ {
+ readBuffer.pullContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
+ int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)});
+ while ((readBuffer.hasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding-- > 0)) {
+ // Just read the padding data and ignore it
+ ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)};
+ }
+ readBuffer.closeContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
+ }
+ <#break>
+ <#case "reserved">
+ <#assign reservedField = field.asReservedField().orElseThrow()>
+ <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+ {
+ ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall("reserved", simpleTypeReference, "", reservedField)};
+ if(reserved != ${helper.getReservedValue(reservedField)}) {
+ LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field.");
+ }
+ }
+ <#break>
+ <#case "simple">
+ <#assign simpleField = field.asSimpleField().orElseThrow()>
+
+ <#if !helper.isSimpleTypeReference(simpleField.type)>
+ readBuffer.pullContext("${simpleField.name}");
+ </#if>
+
+ // Simple Field (${simpleField.name})
+ <@compress single_line=true>
+ ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} =
+ <#assign simpleFieldLogicalName><#if helper.isSimpleTypeReference(simpleField.type)>${simpleField.name}<#else>${simpleField.typeName}</#if></#assign>
+ <#if helper.isEnumField(simpleField)>
+ /* enum based simple field with type ${simpleField.type.name} */
+ ${helper.getLanguageTypeNameForField(simpleField)}.enumForValue(
+ ${helper.getReadBufferReadMethodCall(simpleField.type.name, helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)}
+ );
+ <#elseif helper.isComplexTypeReference(simpleField.type)>
+ <#assign complexTypeReference = simpleField.type.asComplexTypeReference().orElseThrow()>
+ <#assign typeName=complexTypeReference.name>
+ <#assign typeDefinition = helper.getTypeDefinitionForTypeReference(complexTypeReference)>
+ <#if typeDefinition.isDiscriminatedChildTypeDefinition()>
+ <#-- Usually you don't use child directly unless they are parameterized #-->
+ <#assign typeName=typeDefinition.parentType.name>
+ <#assign typeDefinition=typeDefinition.parentType>
+ </#if>
+ <#-- We downcast to the referenced type -->
+ (${simpleField.type.name}) ${typeName}IO.staticParse(readBuffer
+ <#if field.params.isPresent()>,
+ <#list field.params.orElseThrow() as parserArgument>
+ <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true) = 'String'>
+ ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true)}
+ .valueOf(${helper.toParseExpression(simpleField, parserArgument, parserArguments)})<#sep>, </#sep>
+ <#else>
+ (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(complexTypeReference, parserArgument?index), true)})
+ (${helper.toParseExpression(simpleField, parserArgument, parserArguments)})<#sep>, </#sep>
+ </#if>
+ </#list>
+ </#if>
+ <#if complexTypeReference.params.isPresent() && typeDefinition.parserArguments.isPresent()>
+ <#assign argumentOffset=0>
+ <#if field.params.isPresent()><#assign argumentOffset=field.params.orElseThrow()?size></#if>
+ ,
+ <#list complexTypeReference.params.orElseThrow() as typeParam>
+ <#-- We cast here explicitly as java sometimes can't infer the type. e.g. 0 is a int and not a byte#-->
+ (${helper.getLanguageTypeNameForTypeReference(typeDefinition.parserArguments.orElseThrow()[typeParam?index + argumentOffset].type, true)})
+ ${helper.toAccessExpression(null, typeParam, null)}<#sep>, </#sep>
+ </#list>
+ </#if>
+ )
+ <#else>
+ ${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}
+ </#if>
+ ;
+ </...@compress>
+
+ <#if !helper.isSimpleTypeReference(simpleField.type)>
+ readBuffer.closeContext("${simpleField.name}");
+ </#if>
+
+ <#break>
+ <#case "switch">
+ <#assign switchField = field.asSwitchField().orElseThrow()>
+
+ // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
+ ${type.name}Builder builder = null;
+ <#list switchField.cases as case>
+ <@compress single_line=true>
+ <#if case.discriminatorValues?has_content>
+ if(
+ <#list case.discriminatorValues as discriminatorValue>
+ <#assign discriminatorExpression=switchField.discriminatorExpressions[discriminatorValue?index].asLiteral().orElseThrow().asVariableLiteral().orElseThrow()>
+ EvaluationHelper.equals(
+ ${helper.toParseExpression(null, discriminatorExpression, parserArguments)},
+ <#if helper.discriminatorValueNeedsStringEqualityCheck(discriminatorExpression)>
+ ${tracer.dive("discriminatorValueNeedsStringEqualityCheck")}"${discriminatorValue}"
+ <#elseif helper.isComplexTypeReference(helper.getDiscriminatorTypes()[discriminatorExpression.name])>
+ <#if helper.isEnumTypeReference(helper.getDiscriminatorTypes()[discriminatorExpression.name])>
+ ${tracer.dive("isEnumTypeReference")}${helper.getDiscriminatorTypes()[discriminatorExpression.name].asComplexTypeReference().orElseThrow().name}.${discriminatorValue}
+ <#else>
+ ${tracer.dive("!isEnumTypeReference")}${discriminatorValue}
+ </#if>
+ <#else>
+ ${tracer.dive("else")}${discriminatorValue}
+ </#if>
+ )
+ <#sep> && </#sep>
+ </#list>
+ )
+ </#if>{
+ </...@compress>
+ <@compress single_line=true>
+ <#assign hasCaseParseArguments=case.parserArguments.isPresent() && case.parserArguments.orElseThrow()?has_content>
+ <#assign caseParseArguments><#if hasCaseParseArguments><#list case.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ <#-- We expose the parentParserArguments to the child here too-->
+ <#assign hasParentCaseParseArguments=case.parentType?? && case.parentType.parserArguments.isPresent() && case.parentType.parserArguments.orElseThrow()?filter(arg -> hasCaseParseArguments && !case.parserArguments.orElseThrow()?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments)?has_content>
+ <#assign parentCaseParseArguments><#if hasParentCaseParseArguments><#list case.parentType.parserArguments.orElseThrow()?filter(arg -> hasCaseParseArguments && !case.parserArguments.orElseThrow()?map(argument->argument.name)?seq_contains(arg.name) || !hasCaseParseArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
+ builder = ${case.name}IO.staticParse(readBuffer<#if hasCaseParseArguments>, ${tracer.dive("case parse arguments")} ${caseParseArguments}</#if><#if hasParentCaseParseArguments>, ${tracer.dive("case parent parse arguments")} ${parentCaseParseArguments}</#if>);
+ </...@compress>
+ }<#sep> else </#sep>
+ </#list>
+ if (builder == null) {
+ throw new ParseException("Unsupported case for discriminated type");
+ }
+ <#break>
+
+ <#case "unknown">
+ <#assign unknownField = field.asUnknownField().orElseThrow()>
+ <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Unknown Field
+ ${helper.getReadBufferReadMethodCall("unknown" , simpleTypeReference, "", unknownField)};
+ <#break>
+
+ <#case "virtual">
+ <#assign virtualField = field.asVirtualField().orElseThrow()>
+
+ // Virtual field (Just declare a local variable so we can access it in the parser)
+ <#if helper.getLanguageTypeNameForField(field) = 'String'>
+ ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)});
+ <#else>
+ ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, parserArguments)});
+ </#if>
+ <#break>
+</#switch>
+</#list>
+
+ readBuffer.closeContext("${type.name}");
+ // Create the instance
+ <#if type.isDiscriminatedChildTypeDefinition()>
+ return new ${type.name}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+ <#elseif type.isDiscriminatedParentTypeDefinition()>
+ return builder.build(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+ <#else>
+ return new ${type.name}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>);
+ </#if>
+ }
+
+<#if outputFlavor != "passive">
+ public static void staticSerialize(WriteBuffer writeBuffer, ${type.name} _value<#if helper.getSerializerArguments(parserArguments)?has_content>, <#list helper.getSerializerArguments(parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+ <#if helper.hasFieldOfType("unknown")>
+ throw new ParseException("Unknown field not serializable");
+ <#else>
+ int startPos = writeBuffer.getPos();
+ writeBuffer.pushContext("${type.name}");
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "array">
+ <#assign arrayField = field.asArrayField().orElseThrow()>
+
+ // Array Field (${arrayField.name})
+ if(_value.get${arrayField.name?cap_first}() != null) {
+ <#if arrayField.type.isByteBased()>
+ // Byte Array field (${arrayField.name})
+ writeBuffer.writeByteArray("${arrayField.name}", _value.get${arrayField.name?cap_first}());
+ <#else>
+ writeBuffer.pushContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ int itemCount = (int) _value.get${arrayField.name?cap_first}().length;
+ int curItem = 0;
+ for(${helper.getLanguageTypeNameForField(arrayField)} element : _value.get${arrayField.name?cap_first}()) {
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
+ ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "element", arrayField)};
+ <#else>
+ <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
+ boolean lastItem = curItem == (itemCount - 1);
+ ${complexTypeReference.name}IO.staticSerialize(writeBuffer, element<#if helper.getSerializerTerms(field.params.orElse(null))?has_content>, <#list helper.getSerializerTerms(field.params.orElseThrow()) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+ </#if>
+ curItem++;
+ }
+ writeBuffer.popContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ </#if>
+ }
+ <#break>
+ <#case "checksum">
+ <#assign checksumField = field.asChecksumField().orElseThrow()>
+ <#assign simpleTypeReference = checksumField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Checksum Field (checksum) (Calculated)
+ {
+ ${helper.getLanguageTypeNameForField(field)} _checksum = ${helper.getNullValueForTypeReference(checksumField.type)};
+ _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, parserArguments)});
+ ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", checksumField)};
+ }
+ <#break>
+ <#case "const">
+ <#assign constField = field.asConstField().orElseThrow()>
+
+ // Const Field (${constField.name})
+ <#if helper.isSimpleTypeReference(constField.type)>
+ <#assign simpleTypeReference = constField.type.asSimpleTypeReference().orElseThrow()>
+ <#if helper.getLanguageTypeNameForField(field) = 'float'>
+ ${helper.getWriteBufferWriteMethodCall(simpleTypeReference, constField.referenceValue + "f", constField)};
+ <#else>
+ ${helper.getWriteBufferWriteMethodCall(constField.name, simpleTypeReference, constField.referenceValue, constField)};
+ </#if>
+ <#else>
+ <#assign enumTypeReference = constField.type>
+ ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumTypeReference).name, helper.getEnumBaseTypeReference(enumTypeReference), "(" + type.name + "." + constField.name?upper_case + ".getValue())", constField, "WithReaderWriterArgs.WithAdditionalStringRepresentation("+ type.name + "." + constField.name?upper_case + ".name())")};
+ </#if>
+ <#break>
+ <#case "discriminator">
+ <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
+
+ // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
+ ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${discriminatorField.name?cap_first}();
+ <#if helper.isSimpleTypeReference(discriminatorField.type)>
+ <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
+ ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", discriminatorField)};
+ <#else>
+ <#assign complexTypeReference = discriminatorField.type>
+ <#if helper.isEnumField(field)>
+ ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "(" + discriminatorField.name + ".getValue())", discriminatorField)};
+ <#else>
+ ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${discriminatorField.name});
+ </#if>
+ </#if>
+ <#break>
+ <#case "enum">
+ <#assign enumField = field.asEnumField().orElseThrow()>
+
+ writeBuffer.pushContext("${enumField.name}");
+ // Enum field (${enumField.name})
+ ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(enumField)}) _value.get${enumField.name?cap_first}();
+ <#if enumField.fieldName.isPresent()>
+ ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName.orElseThrow()), "(" + enumField.name + ".get" + enumField.fieldName.orElseThrow()?cap_first + "())", enumField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
+ <#else>
+ ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "(" + enumField.name + ".getValue())", enumField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")};
+ </#if>
+ writeBuffer.popContext("${enumField.name}");
+ <#break>
+ <#case "implicit">
+ <#assign implicitField = field.asImplicitField().orElseThrow()>
+ <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
+ ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, parserArguments)});
+ ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", implicitField)};
+ <#break>
+ <#case "manualArray">
+ <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
+
+ // Manual Array Field (${manualArrayField.name})
+ if(_value.get${manualArrayField.name?cap_first}() != null) {
+ writeBuffer.pushContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ for(${helper.getLanguageTypeNameForField(field)} element : _value.get${manualArrayField.name?cap_first}()) {
+ ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, parserArguments)};
+ }
+ writeBuffer.popContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
+ }
+ <#break>
+ <#case "manual">
+ <#assign manualField = field.asTypedField().orElseThrow()>
+
+ // Manual Field (${manualField.name})
+ ${helper.toSerializationExpression(manualField, manualField.serializeExpression, parserArguments)};
+ <#break>
+ <#case "optional">
+ <#assign optionalField = field.asOptionalField().orElseThrow()>
+
+ // Optional Field (${optionalField.name}) (Can be skipped, if the value is null)
+ ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null;
+ if(_value.get${optionalField.name?cap_first}() != null) {
+ ${optionalField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${optionalField.name?cap_first}();
+ <#if helper.isSimpleTypeReference(optionalField.type)>
+ <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
+ ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "(" + optionalField.name + ")", optionalField)};
+ <#else>
+ <#assign complexTypeReference = optionalField.type>
+ <#if helper.isEnumField(field)>
+ ${helper.getWriteBufferWriteMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "(" + optionalField.name + ".getValue())", optionalField)};
+ <#else>
+ ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${optionalField.name});
+ </#if>
+ </#if>
+ }
+ <#break>
+ <#case "padding">
+ <#assign paddingField = field.asPaddingField().orElseThrow()>
+ <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Padding Field (padding)
+ {
+ writeBuffer.pushContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
+ int _timesPadding = (int) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, parserArguments)});
+ while (_timesPadding-- > 0) {
+ ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, parserArguments)});
+ ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", paddingField)};
+ }
+ writeBuffer.popContext("padding", WithReaderWriterArgs.WithRenderAsList(true));
+ }
+ <#break>
+ <#case "reserved">
+ <#assign reservedField = field.asReservedField().orElseThrow()>
+ <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
+
+ // Reserved Field (reserved)
+ ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(reservedField), reservedField)};
+ <#break>
+ <#case "simple">
+ <#assign simpleField = field.asSimpleField().orElseThrow()>
+
+ // Simple Field (${simpleField.name})
+ ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${simpleField.name?cap_first}();
+ <#if helper.isSimpleTypeReference(simpleField.type)>
+ <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
+ <#if helper.isEnumField(field)>
+ // enum based simple field with type ${simpleField.type.asComplexTypeReference().orElseThrow().name}
+ ${helper.getWriteBufferWriteMethodCall(simpleField.type.asComplexTypeReference().orElseThrow().name, simpleTypeReference, "(" + simpleField.name + ")", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
+ <#else>
+ ${helper.getWriteBufferWriteMethodCall(simpleField.name, simpleTypeReference, "(" + simpleField.name + ")", simpleField)};
+ </#if>
+ <#else>
+ writeBuffer.pushContext("${simpleField.name}");
+ <#assign complexTypeReference = simpleField.type>
+ <#if helper.isEnumField(field)>
+ // enum field with type ${complexTypeReference.name}
+ ${helper.getWriteBufferWriteMethodCall(complexTypeReference.name, helper.getEnumBaseTypeReference(simpleField.type), "(" + simpleField.name + ".getValue())", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")};
+ <#else>
+ ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${simpleField.name});
+ </#if>
+ writeBuffer.popContext("${simpleField.name}");
+ </#if>
+ <#break>
+ <#case "switch">
+ <#assign switchField = field.asSwitchField().orElseThrow()>
+
+ // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
+ <#list switchField.cases as case>
+ if(_value instanceof ${case.name}) {
+ ${case.name}IO.staticSerialize(writeBuffer, (${case.name}) _value);
+ }<#sep> else </#sep>
+ </#list>
+ <#break>
+ <#case "virtual">
+ <#break>
+</#switch>
+</#list>
+ writeBuffer.popContext("${type.name}");
+ </#if>
+ }
+</#if>
+
+<#if type.isDiscriminatedParentTypeDefinition()>
+ public static interface ${type.name}Builder {
+ ${type.name} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>);
+ }
+
+</#if>
+<#if type.isDiscriminatedChildTypeDefinition()>
+ public static class ${type.name}Builder implements ${type.parentType.name}IO.${type.parentType.name}Builder {
+ <#if type.propertyFields?has_content>
+ <#list type.propertyFields as field>
+ private final ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name};
+ </#list>
+ </#if>
+
+ public ${type.name}Builder(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+ <#list type.propertyFields as field>
+ this.${field.name} = ${field.name};
+ </#list>
+ }
+
+ public ${type.name} build(<#list type.parentType.asComplexTypeDefinition().orElseThrow().propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+ return new ${type.name}(<#list type.allPropertyFields as field>${field.name}<#sep>, </#sep></#list>);
+ }
+ }
+
+</#if>
+}
+</#outputformat>
diff --git a/code-generation/language-java-ng/src/main/resources/templates/java/pojo-template.java.ftlh b/code-generation/language-java-ng/src/main/resources/templates/java/pojo-template.java.ftlh
new file mode 100644
index 0000000..e34be2e
--- /dev/null
+++ b/code-generation/language-java-ng/src/main/resources/templates/java/pojo-template.java.ftlh
@@ -0,0 +1,394 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<#-- Prevent freemarker from escaping stuff -->
+<#outputformat "undefined">
+<#-- Declare the name and type of variables passed in to the template -->
+<#-- @ftlvariable name="languageName" type="java.lang.String" -->
+<#-- @ftlvariable name="protocolName" type="java.lang.String" -->
+<#-- @ftlvariable name="outputFlavor" type="java.lang.String" -->
+<#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
+<#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
+<#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+<#-- Declare the name and type of variables declared locally inside the template -->
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 ${helper.packageName(protocolName, languageName, outputFlavor)};
+
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;
+import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.spi.generation.Message;
+import org.apache.plc4x.java.spi.generation.MessageIO;
+
+import java.time.*;
+import java.util.*;
+import java.math.BigInteger;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+<#-- TODO: the code below implies that parserArguments will be null if not present... not pretty -->
+<#if type.parserArguments.isPresent()><#assign parserArguments=type.parserArguments.orElseThrow()></#if>
+public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.parentType??> extends ${type.parentType.name}</#if> implements Message {
+
+<#--
+ If this is a discriminated child type, we need to generate methods for accessing it's discriminator
+ values, as if they were normal java properties.
+-->
+<#if type.isDiscriminatedChildTypeDefinition()>
+ <#assign discriminatedChildType = type.asDiscriminatedComplexTypeDefinition().orElseThrow()>
+ // Accessors for discriminator values.
+ <#list discriminatedChildType.getDiscriminatorMap() as discriminatorName, discriminatorValue>
+ <#-- If the discriminator name matches that of another field, suppress the methods generation -->
+ <#if !discriminatedChildType.isNonDiscriminatorField(discriminatorName)>
+ public ${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])} get${discriminatorName?cap_first}() {
+ <#if !helper.isComplexTypeReference(helper.getDiscriminatorTypes()[discriminatorName])>
+ return <#if helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName]) = "String"><#if discriminatorValue??>"${discriminatorValue}"<#else>${helper.getNullValueForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])}</#if><#else><#if discriminatorValue??>${helper.adjustLiterals(helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName]),discriminatorValue)}<#else>${helper.getNullValueForTypeReference( [...]
+ <#else>
+ return <#if helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName]) = "String"><#if discriminatorValue??>"${discriminatorValue}"<#else>${helper.getNullValueForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])}</#if><#else><#if discriminatorValue??>${helper.getLanguageTypeNameForTypeReference(helper.getDiscriminatorTypes()[discriminatorName])}.${discriminatorValue}<#else>${helper.getLanguageTypeNameForTypeReference(helper.getDis [...]
+ </#if>
+ }
+ </#if>
+ </#list>
+</#if>
+<#--
+ If this is a discriminated parent type, we need to generate the abstract methods for accessing it's
+ discriminator values instead.
+-->
+<#if type.isDiscriminatedParentTypeDefinition()>
+ <#assign discriminatedParentType = type>
+ <#-- @ftlvariable name="discriminatedParentType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
+ // Abstract accessors for discriminator values.
+ <#list helper.discriminatorTypes as discriminatorName, discriminatorType>
+ <#-- If the discriminator name matches that of another field, suppress the methods generation -->
+ <#if !type.isNonDiscriminatorField(discriminatorName)>
+ public abstract ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}();
+ </#if>
+ </#list>
+</#if>
+<#-- If the current type contains "const" fields, generate some java constants for holing their values -->
+<#if type.constFields?has_content>
+
+ // Constant values.
+<#list type.constFields as field>
+ public static final ${helper.getLanguageTypeNameForField(field)} ${field.name?upper_case} = <#if helper.getLanguageTypeNameForField(field) = 'float'>${field.referenceValue}f<#else>${field.referenceValue}</#if>;
+</#list>
+</#if>
+<#-- Property fields are fields that require a property in the pojo -->
+<#if type.propertyFields?has_content>
+
+ // Properties.
+<#list type.propertyFields as field>
+ private final ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name};
+</#list>
+</#if>
+
+ <#-- getAllPropertyFields() returns not only the property fields of this type but also of it's parents -->
+ public ${type.name}(<#list type.getAllPropertyFields() as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) {
+<#if type.getParentPropertyFields()?has_content>
+ super(<#list type.getParentPropertyFields() as field>${field.name}<#sep>, </#sep></#list>);
+</#if>
+<#list type.propertyFields as field>
+ this.${field.name} = ${field.name};
+</#list>
+ }
+
+<#list type.abstractFields as field>
+ public abstract ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.asNamedField().orElseThrow().name?cap_first}();
+
+</#list>
+<#list type.propertyFields as field>
+ public ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.name?cap_first}() {
+ return ${field.name};
+ }
+
+</#list>
+<#list type.virtualFields as field>
+ <#if !type.isDiscriminatorField(field.name)>
+ public ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> get${field.name?cap_first}() {
+ <#if helper.getLanguageTypeNameForField(field) = 'String'>
+ return ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toAccessExpression(field, field.valueExpression, parserArguments)});
+ <#else>
+ return (${helper.getLanguageTypeNameForField(field)}) (${helper.toAccessExpression(field, field.valueExpression, parserArguments)});
+ </#if>
+ }
+ </#if>
+
+</#list>
+ @Override
+ public int getLengthInBytes() {
+ return getLengthInBits() / 8;
+ }
+
+ @Override
+ public int getLengthInBits() {
+ return getLengthInBitsConditional(false);
+ }
+
+<#-- TODO: use serializer args instead of a fixed bool for one case -->
+ public int getLengthInBitsConditional(boolean lastItem) {
+ int lengthInBits = <#if type.parentType??>super.getLengthInBitsConditional(lastItem)<#else>0</#if>;
+ ${helper.getLanguageTypeNameForTypeReference(type.typeReference)} _value = this;
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "array">
+ <#assign arrayField = field.asArrayField().orElseThrow()>
+
+ // Array field
+ if(${arrayField.name} != null) {
+ <#if helper.isSimpleTypeReference(arrayField.type)>
+ <#assign simpleTypeReference = arrayField.type.asSimpleTypeReference().orElseThrow()>
+ lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.length;
+ <#elseif arrayField.isCountArrayField()>
+ int i=0;
+ <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
+ for(${complexTypeReference.name} element : ${arrayField.name}) {
+ boolean last = ++i >= ${arrayField.name}.length;
+ lengthInBits += element.getLengthInBitsConditional(last);
+ }
+ <#else>
+ for(Message element : ${arrayField.name}) {
+ lengthInBits += element.getLengthInBits();
+ }
+ </#if>
+ }
+ <#break>
+ <#case "checksum">
+ <#assign checksumField = field>
+ <#assign simpleTypeReference = checksumField.type>
+
+ // Checksum Field (checksum)
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ <#break>
+ <#case "const">
+ <#assign constField = field>
+ <#assign typeReference = constField.type>
+
+ // Const Field (${constField.name})
+ <#if helper.isSimpleTypeReference(typeReference)>
+ <#assign simpleTypeReference = typeReference>
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ <#else>
+ lengthInBits += ${helper.getEnumBaseTypeReference(typeReference).sizeInBits};
+ </#if>
+ <#break>
+ <#case "discriminator">
+ <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
+
+ // Discriminator Field (${discriminatorField.name})
+ <#if helper.isSimpleTypeReference(discriminatorField.type)>
+ <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
+ <#if helper.getLanguageTypeNameForTypeReference(discriminatorField.type) = "String">
+ lengthInBits += ${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), parserArguments)};
+ <#else>
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ </#if>
+ <#elseif helper.isEnumField(field)>
+ lengthInBits += ${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};
+ <#else>
+ lengthInBits += ${discriminatorField.name}.getLengthInBits();
+ </#if>
+ <#break>
+ <#case "enum">
+ <#assign enumField = field>
+
+ // Enum Field (${enumField.name})
+ lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
+ <#break>
+ <#case "implicit">
+ <#assign implicitField = field.asImplicitField().orElseThrow()>
+ <#assign simpleTypeReference = implicitField.type>
+
+ // Implicit Field (${implicitField.name})
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ //${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, parserArguments)});
+ <#break>
+ <#case "manualArray">
+ <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
+
+ // Manual Array Field (${manualArrayField.name})
+ lengthInBits += ${helper.toParseExpression(manualArrayField, manualArrayField.lengthExpression, parserArguments)} * 8;
+ <#break>
+ <#case "manual">
+ <#assign manualField = field.asManualField().orElseThrow()>
+
+ // Manual Field (${manualField.name})
+ lengthInBits += ${helper.toParseExpression(manualField, manualField.lengthExpression, parserArguments)} * 8;
+ <#break>
+ <#case "optional">
+ <#assign optionalField = field.asOptionalField().orElseThrow()>
+
+ // Optional Field (${optionalField.name})
+ if(${optionalField.name} != null) {
+ <#if helper.isSimpleTypeReference(optionalField.type)>
+ <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
+ <#if helper.getLanguageTypeNameForTypeReference(optionalField.type) = "String">
+ lengthInBits += ${helper.toSerializationExpression(discriminatorField, simpleTypeReference.getLengthExpression(), parserArguments)};
+ <#else>
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ </#if>
+ <#elseif helper.isEnumField(field)>
+ lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits};
+ <#else>
+ lengthInBits += ${optionalField.name}.getLengthInBits();
+ </#if>
+ }
+ <#break>
+ <#case "padding">
+ <#assign paddingField = field.asPaddingField().orElseThrow()>
+ <#assign simpleTypeReference = paddingField.type>
+
+ // Padding Field (padding)
+ <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
+ int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, parserArguments)});
+ while (_timesPadding-- > 0) {
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ }
+ <#break>
+ <#case "reserved">
+ <#assign reservedField = field>
+ <#assign simpleTypeReference = reservedField.type>
+
+ // Reserved Field (reserved)
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ <#break>
+ <#case "simple">
+ <#assign simpleField = field.asSimpleField().orElseThrow()>
+
+ // Simple field (${simpleField.name})
+ <#if helper.isSimpleTypeReference(simpleField.type)>
+ <#if helper.getLanguageTypeNameForTypeReference(simpleField.type) = "String">
+ <#assign stringTypeReference = simpleField.type.asStringTypeReference().orElseThrow()>
+ lengthInBits += ${helper.toSerializationExpression(simpleField, stringTypeReference.getLengthExpression(), parserArguments)};
+ <#else>
+ <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ </#if>
+ <#elseif helper.isEnumField(field)>
+ lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
+ <#else>
+ lengthInBits += ${simpleField.name}.getLengthInBits();
+ </#if>
+ <#break>
+ <#case "switch">
+ <#assign switchField = field>
+
+ // Length of sub-type elements will be added by sub-type...
+ <#break>
+ <#case "unknown">
+ <#assign unknownField = field>
+ <#assign simpleTypeReference = unknownField.type>
+
+ // Unknown field
+ lengthInBits += ${simpleTypeReference.sizeInBits};
+ <#case "virtual">
+ <#assign virtualField = field>
+
+ // A virtual field doesn't have any in- or output.
+ <#break>
+</#switch>
+</#list>
+
+ return lengthInBits;
+ }
+
+ @Override
+ public MessageIO<<#if type.parentType??>${type.parentType.name}<#else>${type.name}</#if>, <#if type.parentType??>${type.parentType.name}<#else>${type.name}</#if>> getMessageIO() {
+ return new <#if type.parentType??>${type.parentType.name}<#else>${type.name}</#if>IO();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ${type.name})) {
+ return false;
+ }
+ ${type.name} that = (${type.name}) o;
+ return
+ <#if type.propertyFields?has_content>
+ <#list type.propertyFields as field>
+ (get${field.name?cap_first}() == that.get${field.name?cap_first}()) &&
+ </#list>
+ </#if>
+ <#if type.parentType??>
+ super.equals(that) &&
+ </#if>
+ true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ <#if type.parentType??>
+ super.hashCode()<#if type.propertyFields?has_content>,</#if>
+ </#if>
+ <#if type.propertyFields?has_content>
+ <#list type.propertyFields as field>
+ get${field.name?cap_first}()<#sep>,</#sep>
+ </#list>
+ </#if>
+ );
+ }
+
+ @Override
+ public String toString() {
+ return toString(ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+
+ public String toString(ToStringStyle style) {
+ return new ToStringBuilder(this, style)
+ <#if type.parentType??>
+ .appendSuper(super.toString(style))
+ </#if>
+ <#if type.propertyFields?has_content>
+ <#list type.propertyFields as field>
+ .append("${field.name}", get${field.name?cap_first}())
+ </#list>
+ </#if>
+ <#list type.virtualFields as field>
+ .append("${field.name}", get${field.name?cap_first}())
+ </#list>
+ .toString();
+ }
+
+}
+</#outputformat>
\ No newline at end of file
diff --git a/code-generation/language-java-ng/src/test/resources/integration-test/pom.xml b/code-generation/language-java-ng/src/test/resources/integration-test/pom.xml
new file mode 100644
index 0000000..21530ff
--- /dev/null
+++ b/code-generation/language-java-ng/src/test/resources/integration-test/pom.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation</artifactId>
+ <version>@project.version@</version>
+ <relativePath>../../../..</relativePath>
+ </parent>
+
+ <artifactId>plc4j-java-mspec-test</artifactId>
+
+ <name>PLC4J: Driver: Java Mpsec Test</name>
+ <description></description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-maven-plugin</artifactId>
+ <version>${plc4x-code-generation.version}</version>
+ <executions>
+ <execution>
+ <id>generate-driver</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate-driver</goal>
+ </goals>
+ <configuration>
+ <protocolName>test</protocolName>
+ <languageName>java</languageName>
+ <outputFlavor>read-write</outputFlavor>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-feature-xml</id>
+ <phase>compile</phase>
+ <goals>
+ <!-- Generate the feature.xml -->
+ <goal>features-generate-descriptor</goal>
+ <!-- Check the feature.xml -->
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <enableGeneration>true</enableGeneration>
+ <aggregateFeatures>true</aggregateFeatures>
+ </configuration>
+ </execution>
+ <execution>
+ <id>build-kar</id>
+ <phase>package</phase>
+ <goals>
+ <!--
+ Build a kar archive (Jar containing the feature.xml
+ as well as the module content and it's dependencies.
+ -->
+ <goal>kar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Activator>org.apache.plc4x.java.osgi.DriverActivator</Bundle-Activator>
+ <Export-Service>org.apache.plc4x.java.api.PlcDriver,org.apache.plc4x.protocol.test
+ </Export-Service>
+ <Import-Package>
+ com.fasterxml.jackson.annotation;resolution:=optional,
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <configuration>
+ <usedDependencies combine.children="append">
+ <usedDependency>org.apache.plc4x:plc4x-code-generation-language-java</usedDependency>
+ <usedDependency>org.apache.plc4x:plc4x-code-generation-protocol-test</usedDependency>
+ </usedDependencies>
+ </configuration>
+ </plugin>
+
+ <!--
+ Make the failsafe execute all integration-tests
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!--
+ Notice the @ instead of the $ as prefix? That's late evaluation.
+ -->
+ <!--argLine>@{failsafeArgLine}</argLine-->
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+<dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-api</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-spi</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-transport-tcp</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-buffer</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-utils-test-utils</artifactId>
+ <version>@project.version@</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-language-java</artifactId>
+ <version>@project.version@</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-test</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-test</artifactId>
+ <version>@project.version@</version>
+ <classifier>tests</classifier>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
+
diff --git a/code-generation/language-java-ng/src/test/resources/settings.xml b/code-generation/language-java-ng/src/test/resources/settings.xml
new file mode 100644
index 0000000..2eb8990
--- /dev/null
+++ b/code-generation/language-java-ng/src/test/resources/settings.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+ -->
+<settings>
+ <profiles>
+ <profile>
+ <id>it-repo</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <repositories>
+ <repository>
+ <id>local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ </profile>
+ </profiles>
+</settings>
\ No newline at end of file
diff --git a/code-generation/pom.xml b/code-generation/pom.xml
index cb7e142..be95f65 100644
--- a/code-generation/pom.xml
+++ b/code-generation/pom.xml
@@ -39,6 +39,7 @@
<module>protocol-test</module>
<module>language-java</module>
+ <module>language-java-ng</module>
</modules>
<profiles>
diff --git a/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 b/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
index 0a3edd4..fe8bbfa 100644
--- a/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
+++ b/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
@@ -151,8 +151,8 @@ dataType
| base='byte'
| base='int' size=INTEGER_LITERAL
| base='uint' size=INTEGER_LITERAL
- | base='float' exponent=INTEGER_LITERAL '.' mantissa=INTEGER_LITERAL
- | base='ufloat' exponent=INTEGER_LITERAL '.' mantissa=INTEGER_LITERAL
+ | base='float' size=INTEGER_LITERAL
+ | base='ufloat' size=INTEGER_LITERAL
| base='string' size=INTEGER_LITERAL
| base='vstring' (length=expression)?
| base='time'
diff --git a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
index e2f060c..f5be727 100644
--- a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
+++ b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
@@ -73,8 +73,8 @@
/*
* TODO: doesn't compile in java
[type 'UFloatTypeTest'
- [simple ufloat 8.23 'ufloatField']
- [simple ufloat 11.52 'udoubleField']
+ [simple ufloat 32 'ufloatField']
+ [simple ufloat 64 'udoubleField']
]
*/
@@ -92,8 +92,8 @@
[simple byte 'byteField']
[simple int 8 'intField']
[simple uint 8 'uintField']
- [simple float 8.23 'floatField']
- [simple float 11.52 'doubleField']
+ [simple float 32 'floatField']
+ [simple float 64 'doubleField']
[simple string 8 'stringField']
]
@@ -103,16 +103,16 @@
[abstract bit 'abstractBitField']
[abstract int 8 'abstractIntField']
[abstract uint 8 'abstractUintField']
- [abstract float 8.23 'abstractFloatField']
- [abstract float 11.52 'abstractDoubleField']
+ [abstract float 32 'abstractFloatField']
+ [abstract float 64 'abstractDoubleField']
[abstract string 8 'abstractStringField']
[typeSwitch 'simpleField'
['0' AbstractedType
[simple bit 'abstractBitField']
[simple int 8 'abstractIntField']
[simple uint 8 'abstractUintField']
- [simple float 8.23 'abstractFloatField']
- [simple float 11.52 'abstractDoubleField']
+ [simple float 32 'abstractFloatField']
+ [simple float 64 'abstractDoubleField']
[simple string 8 'abstractStringField']
]
]
@@ -124,8 +124,8 @@
[abstract bit 'abstractBitField']
[abstract int 8 'abstractIntField']
[abstract uint 8 'abstractUintField']
- [abstract float 8.23 'abstractFloatField']
- [abstract float 11.52 'abstractDoubleField']
+ [abstract float 32 'abstractFloatField']
+ [abstract float 64 'abstractDoubleField']
[abstract string 8 'abstractStringField']
[typeSwitch 'simpleField'
['0' AbstractedType
@@ -133,8 +133,8 @@
[simple bit 'abstractBitField']
[simple int 8 'abstractIntField']
[simple uint 8 'abstractUintField']
- [simple float 8.23 'abstractFloatField']
- [simple float 11.52 'abstractDoubleField']
+ [simple float 32 'abstractFloatField']
+ [simple float 64 'abstractDoubleField']
[simple string 8 'abstractStringField']
]
]
@@ -144,8 +144,8 @@
[array bit 'bitField' count '5']
[array int 8 'intField' count '5']
[array uint 8 'uintField' count '5']
- [array float 8.23 'floatField' count '5']
- [array float 11.52 'doubleField' count '5']
+ [array float 32 'floatField' count '5']
+ [array float 64 'doubleField' count '5']
[array string 8 'stringField' count '5']
]
@@ -156,8 +156,8 @@
//[checksum int 8 'intField' '100']
//[checksum uint 8 'uintField' '100']
//Float fields cannot be used as checksums
- //[checksum float 8.23 'floatField' '100.0f']
- //[checksum float 11.52 'doubleField' '100.0']
+ //[checksum float 32 'floatField' '100.0f']
+ //[checksum float 64 'doubleField' '100.0']
//String field cannot be used as a checksum
//[checksum vstring '11 * 8' 'stringField' '"HELLO TODDY"']
//]
@@ -166,8 +166,8 @@
[const bit 'bitField' 'true']
[const int 8 'intField' '100']
[const uint 8 'uintField' '100']
- [const float 8.23 'floatField' '100.0']
- [const float 11.52 'doubleField' '100.0']
+ [const float 32 'floatField' '100.0']
+ [const float 64 'doubleField' '100.0']
[const string 8 'stringField' '"HELLO TODDY"']
]
@@ -193,8 +193,8 @@
[implicit bit 'bitField' 'simpleField > 0']
[implicit int 8 'intField' 'simpleField']
[implicit uint 8 'uintField' 'simpleField']
- [implicit float 8.23 'floatField' 'simpleField']
- [implicit float 11.52 'doubleField' 'simpleField']
+ [implicit float 32 'floatField' 'simpleField']
+ [implicit float 64 'doubleField' 'simpleField']
//TODO: String literals can't be used in the expression
//[implicit string 8 'stringField' 'simpleField > 0 ? "HELLO TODDY" : "BYE TODDY"']
]
@@ -219,8 +219,8 @@
// [virtual bit 'virtualBitField' 'simpleField == 0']
// [virtual int 8 'virtualIntField' 'simpleField']
// [virtual uint 8 'virtualUintField' 'simpleField']
-// [virtual float 8.23 'virtualFloatField' 'simpleField']
-// [virtual float 11.52 'virtualDoubleField' 'simpleField']
+// [virtual float 32 'virtualFloatField' 'simpleField']
+// [virtual float 64 'virtualDoubleField' 'simpleField']
// [virtual string 24 'virtualStringField' 'simpleField']
//]
@@ -230,8 +230,8 @@
// [virtual bit 'virtualBitField' 'simpleField == 0']
// [virtual int 8 'virtualIntField' 'simpleField']
// [virtual uint 8 'virtualUintField' 'simpleField']
-// [virtual float 8.23 'virtualFloatField' 'simpleField']
-// [virtual float 11.52 'virtualDoubleField' 'simpleField']
+// [virtual float 32 'virtualFloatField' 'simpleField']
+// [virtual float 64 'virtualDoubleField' 'simpleField']
// [virtual string 24 'virtualStringField' 'simpleField']
// [typeSwitch 'simpleField'
// ['0' DiscriminatedVirtualType
@@ -387,14 +387,14 @@
]
//TODO: C doesn't support non integer switch fields
-//[enum float 8.23 'EnumTypeFloat'
+//[enum float 32 'EnumTypeFloat'
// ['100.0' LOW]
// ['101.0' MID]
// ['102.0' BIG]
//]
//TODO: C doesn't support non integer switch fields
-//[enum float 11.52 'EnumTypeDouble'
+//[enum float 64 'EnumTypeDouble'
// ['100.0' LOW]
// ['101.0' MID]
// ['102.0' BIG]
@@ -413,7 +413,7 @@
//]
//TODO: Float parameters aren't implemented for constants in enums in C
-//[enum int 8 'EnumTypeAllTest' [bit 'bitType', int 8 'intType', uint 8 'uintType', float 8.23 'floatType', float 11.52 'doubleType', string 32 'stringType', EnumType 'enumType']
+//[enum int 8 'EnumTypeAllTest' [bit 'bitType', int 8 'intType', uint 8 'uintType', float 32 'floatType', float 64 'doubleType', string 32 'stringType', EnumType 'enumType']
// ['0x01' BOOL ['false' , '1' , '1' , '100.0' , '100.0' , 'BOOL' , 'BOOL']]
// ['0x02' BYTE ['true' , '2' , '2' , '101.1' , '101.1' , 'BYTE' , 'UINT']]
//]
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
new file mode 100644
index 0000000..449ca79
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen;
+
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public interface FieldCommons {
+
+ default Optional<ByteOrder> extractByteOder(WithReaderArgs... readerArgs) {
+ return extractByteOder(Stream.of(readerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+ }
+
+ default Optional<ByteOrder> extractByteOder(WithWriterArgs... writerArgs) {
+ return extractByteOder(Stream.of(writerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+ }
+
+ default Optional<ByteOrder> extractByteOder(WithReaderWriterArgs... readerWriterArgs) {
+ for (WithReaderWriterArgs arg : readerWriterArgs) {
+ if (arg instanceof withOptionByteOrder) {
+ return Optional.of(((withOptionByteOrder) arg).byteOrder());
+ }
+ }
+ return Optional.empty();
+ }
+
+ default <T> T switchByteOrderIfNecessary(RunWrapped<T> runnable, DataReader<T> dataReader, ByteOrder wantedByteOrder) throws ParseException {
+ Objects.requireNonNull(runnable);
+ Objects.requireNonNull(dataReader);
+ ByteOrder currentByteOrder = dataReader.getByteOrder();
+ if (wantedByteOrder == null || currentByteOrder == wantedByteOrder) {
+ return runnable.run();
+ }
+ try {
+ dataReader.setByteOrder(wantedByteOrder);
+ return runnable.run();
+ } finally {
+ dataReader.setByteOrder(currentByteOrder);
+ }
+ }
+
+ @FunctionalInterface
+ interface RunWrapped<T> {
+ T run() throws ParseException;
+ }
+
+}
\ No newline at end of file
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/WithOption.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/WithOption.java
new file mode 100644
index 0000000..f202cab
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/WithOption.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen;
+
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import org.apache.plc4x.java.spi.generation.WithReaderWriterArgs;
+
+public interface WithOption extends WithReaderWriterArgs {
+
+ static WithOption WithByteOrder(ByteOrder byteOrder) {
+ return (withOptionByteOrder) () -> byteOrder;
+ }
+
+ static WithOption WithEncoding(String encoding) {
+ return (withOptionEncoding) () -> encoding;
+ }
+
+ static WithOption WithSerializationContext(String context) {
+ return (withOptionSerializationContext) () -> context;
+ }
+
+}
+
+interface withOptionByteOrder extends WithOption {
+ ByteOrder byteOrder();
+}
+
+interface withOptionEncoding extends WithOption {
+ String encoding();
+}
+
+interface withOptionSerializationContext extends WithOption {
+ String context();
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReader.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReader.java
new file mode 100644
index 0000000..c130ecf
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReader.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.FieldCommons;
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+public interface FieldReader<T> extends FieldCommons {
+
+ T readField(String logicalName, DataReader<T> dataIO, WithReaderArgs... readerArgs) throws ParseException;
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderAbstract.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderAbstract.java
new file mode 100644
index 0000000..6618671
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderAbstract.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderAbstract<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderAbstract.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderArray.java
new file mode 100644
index 0000000..99f37a9
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderArray.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderArray<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderArray.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderAssert.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderAssert.java
new file mode 100644
index 0000000..01b85fa
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderAssert.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderAssert<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderAssert.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderChecksum.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderChecksum.java
new file mode 100644
index 0000000..321a48b
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderChecksum.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderChecksum<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderChecksum.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderConst.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderConst.java
new file mode 100644
index 0000000..e41d3f3
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderConst.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderConst<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderConst.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderDiscriminator.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderDiscriminator.java
new file mode 100644
index 0000000..0f906dc
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderDiscriminator.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderDiscriminator<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderDiscriminator.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderEnum.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderEnum.java
new file mode 100644
index 0000000..755310b
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderEnum.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderEnum<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderEnum.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderImplicit.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderImplicit.java
new file mode 100644
index 0000000..c68e1bc
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderImplicit.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderImplicit<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderImplicit.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java
new file mode 100644
index 0000000..b3e8cda
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManual.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderManual<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderManual.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java
new file mode 100644
index 0000000..c4b5f6a
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderManualArray.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderManualArray<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderManualArray.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java
new file mode 100644
index 0000000..f3b0332
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderOptional.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseAssertException;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderOptional<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderOptional.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+ public T readOptionalField(String logicalName, DataReader<T> dataReader, boolean condition, WithOption... options) throws ParseException {
+ if (!condition) {
+ LOGGER.debug("Condition doesnt match for field {}", logicalName);
+ return null;
+ }
+
+ int curPos = dataReader.getPos();
+ try {
+ return dataReader.read(logicalName, options);
+ } catch (ParseAssertException e) {
+ LOGGER.trace("Assertion doesnt match for field {}", logicalName, e);
+ dataReader.setPos(curPos);
+ return null;
+ }
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderPadding.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderPadding.java
new file mode 100644
index 0000000..c9747e0
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderPadding.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderPadding<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderPadding.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java
new file mode 100644
index 0000000..4e8913e
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderReserved.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderReserved<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderReserved.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderSimple.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderSimple.java
new file mode 100644
index 0000000..3c02c54
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderSimple.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+public class FieldReaderSimple<T> implements FieldReader<T> {
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ return switchByteOrderIfNecessary(() -> dataReader.read(logicalName, readerArgs), dataReader, extractByteOder(readerArgs).orElse(null));
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderTypeSwitch.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderTypeSwitch.java
new file mode 100644
index 0000000..44f78c1
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderTypeSwitch.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderTypeSwitch<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderTypeSwitch.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java
new file mode 100644
index 0000000..0944a0d
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderUnknown.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderUnknown<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderUnknown.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderVirtual.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderVirtual.java
new file mode 100644
index 0000000..00dcbd3
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderVirtual.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataReader;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FieldReaderVirtual<T> implements FieldReader<T> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderVirtual.class);
+
+ @Override
+ public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException("not possible with optional field");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriter.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriter.java
new file mode 100644
index 0000000..90256d6
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriter.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.fields;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.codegen.io.DataWriter;
+
+public interface FieldWriter<T> {
+
+ void writeField(T value, DataWriter<T> dataWriter, WithOption... options);
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java
new file mode 100644
index 0000000..b3f2ceb
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReader.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.ByteOrder;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+public interface DataReader<T> {
+ T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException;
+
+ int getPos();
+
+ void setPos(int position);
+
+ ByteOrder getByteOrder();
+
+ void setByteOrder(ByteOrder byteOrder);
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderComplex.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderComplex.java
new file mode 100644
index 0000000..662ef53
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderComplex.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+import java.util.function.Supplier;
+
+public interface DataReaderComplex<T> extends DataReader<T> {
+
+ T read(String logicalName, Supplier<T> complexSupplier, WithReaderArgs... readerArgs) throws ParseException;
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderComplexDefault.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderComplexDefault.java
new file mode 100644
index 0000000..3f4dca8
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderComplexDefault.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+import java.util.function.Supplier;
+
+public class DataReaderComplexDefault<T> implements DataReaderComplex<T> {
+ private final Supplier<T> complexSupplier;
+
+ // TODO: maybe replace with resetable or something so its clear that that's the only purpose
+ private final ReadBuffer readBuffer;
+
+ public DataReaderComplexDefault(Supplier<T> complexSupplier, ReadBuffer readBuffer) {
+ this.complexSupplier = complexSupplier;
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ @Override
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+
+ @Override
+ public T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
+ return read(logicalName, complexSupplier, readerArgs);
+ }
+
+ public T read(String logicalName, Supplier<T> complexSupplier, WithReaderArgs... readerArgs) throws ParseException {
+ readBuffer.pullContext(logicalName,readerArgs);
+ final T t = complexSupplier.get();
+ readBuffer.closeContext(logicalName,readerArgs);
+ return t;
+ }
+}
+
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderEnum.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderEnum.java
new file mode 100644
index 0000000..fad7756
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderEnum.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+public interface DataReaderEnum<T> extends DataReader {
+
+ T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException;
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderEnumDefault.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderEnumDefault.java
new file mode 100644
index 0000000..0f73266
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderEnumDefault.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithReaderArgs;
+
+import java.util.function.Function;
+
+public class DataReaderEnumDefault<T, I> implements DataReaderEnum<T> {
+
+ private final Function<I, T> enumResolver;
+ private final DataReaderSimple<I> dataReader;
+
+ public DataReaderEnumDefault(Function<I, T> enumResolver, DataReaderSimple<I> dataReader) {
+ this.enumResolver = enumResolver;
+ this.dataReader = dataReader;
+ }
+
+ @Override
+ public int getPos() {
+ return dataReader.getPos();
+ }
+
+ @Override
+ public void setPos(int position) {
+ dataReader.setPos(position);
+ }
+
+ @Override
+ public T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
+ return read(logicalName, enumResolver, readerArgs);
+ }
+
+ public T read(String logicalName, Function<I, T> enumResolver, WithReaderArgs... readerArgs) throws ParseException {
+ // TODO: ensure type safety
+ I rawValue = (I) dataReader.read(logicalName, readerArgs);
+ return enumResolver.apply(rawValue);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java
new file mode 100644
index 0000000..dda35e6
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimple.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public interface DataReaderSimple<T> extends DataReader<T> {
+
+ default T read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
+ throw new IllegalStateException(DataReaderSimple.class.getSimpleName() + " can't be called without a bit length");
+ }
+
+ T read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java
new file mode 100644
index 0000000..a68a74c
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBigDecimal.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.math.BigDecimal;
+
+public class DataReaderSimpleBigDecimal implements DataReaderSimple<BigDecimal> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleBigDecimal(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public BigDecimal read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readBigDecimal(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java
new file mode 100644
index 0000000..418d8bf
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleBoolean.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataReaderSimpleBoolean implements DataReaderSimple<Boolean> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleBoolean(ReadBuffer readBuffer) {
+ this.readBuffer = Objects.requireNonNull(readBuffer);
+ }
+
+ @Override
+ public Boolean read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ if(bitLength != 1) {
+ throw new ParseException("Bit fields only support bitLength of 1");
+ }
+ return readBuffer.readBit(logicalName, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java
new file mode 100644
index 0000000..0cec2da
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByte.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleByte implements DataReaderSimple<Byte> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleByte(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Byte read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ if(bitLength != 8) {
+ throw new ParseException("Byte fields only support bitLength of 8");
+ }
+ return readBuffer.readByte(logicalName, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java
new file mode 100644
index 0000000..c26b558
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleByteArray.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleByteArray implements DataReaderSimple<byte[]> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleByteArray(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public byte[] read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ if (bitLength % 8 != 0) {
+ throw new ParseException("ByteArray fields only support bitLength which are multiples of 8");
+ }
+ return readBuffer.readByteArray(logicalName, bitLength * 8, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java
new file mode 100644
index 0000000..8426dd4
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleDouble.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleDouble implements DataReaderSimple<Double> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleDouble(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Double read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readDouble(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java
new file mode 100644
index 0000000..69f4a28
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleFloat.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleFloat implements DataReaderSimple<Float> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleFloat(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Float read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readFloat(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java
new file mode 100644
index 0000000..df1962e
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedBigInteger.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.math.BigInteger;
+
+public class DataReaderSimpleSignedBigInteger implements DataReaderSimple<BigInteger> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleSignedBigInteger(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public BigInteger read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readBigInteger(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java
new file mode 100644
index 0000000..831a43a
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedByte.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleSignedByte implements DataReaderSimple<Byte> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleSignedByte(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Byte read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readSignedByte(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java
new file mode 100644
index 0000000..30290f9
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedInt.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleSignedInt implements DataReaderSimple<Integer> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleSignedInt(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Integer read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readInt(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java
new file mode 100644
index 0000000..3ddaada
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedLong.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleSignedLong implements DataReaderSimple<Long> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleSignedLong(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Long read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readLong(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java
new file mode 100644
index 0000000..423bc08
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleSignedShort.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleSignedShort implements DataReaderSimple<Short> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleSignedShort(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Short read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readShort(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java
new file mode 100644
index 0000000..7715bea
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedBigInteger.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.math.BigInteger;
+
+public class DataReaderSimpleUnsignedBigInteger implements DataReaderSimple<BigInteger> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleUnsignedBigInteger(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public BigInteger read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readUnsignedBigInteger(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java
new file mode 100644
index 0000000..0aef2b9
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedByte.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleUnsignedByte implements DataReaderSimple<Byte> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleUnsignedByte(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Byte read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readUnsignedByte(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java
new file mode 100644
index 0000000..8f77b4a
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedInt.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleUnsignedInt implements DataReaderSimple<Integer> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleUnsignedInt(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Integer read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readUnsignedInt(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
new file mode 100644
index 0000000..e0631f6
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleUnsignedLong implements DataReaderSimple<Long> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleUnsignedLong(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Long read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readUnsignedLong(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java
new file mode 100644
index 0000000..62e9bac
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedShort.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public class DataReaderSimpleUnsignedShort implements DataReaderSimple<Short> {
+
+ private final ReadBuffer readBuffer;
+
+ public DataReaderSimpleUnsignedShort(ReadBuffer readBuffer) {
+ this.readBuffer = readBuffer;
+ }
+
+ @Override
+ public Short read(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ return readBuffer.readUnsignedShort(logicalName, bitLength, readerArgs);
+ }
+
+ public int getPos() {
+ return readBuffer.getPos();
+ }
+
+ public void setPos(int position) {
+ readBuffer.reset(position);
+ }
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriter.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriter.java
new file mode 100644
index 0000000..19617d7
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriter.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+public interface DataWriter<T> {
+
+ void write(String logicalName, int bitLength, T value, WithWriterArgs... writerArgs) throws ParseException;
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterBigDecimal.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterBigDecimal.java
new file mode 100644
index 0000000..da4ef23
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterBigDecimal.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+
+public class DataWriterBigDecimal implements DataWriter<BigDecimal> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterBigDecimal(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, BigDecimal value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeBigDecimal(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterBoolean.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterBoolean.java
new file mode 100644
index 0000000..bff5a7c
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterBoolean.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterBoolean implements DataWriter<Boolean> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterBoolean(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Boolean value, WithWriterArgs... writerArgs) throws ParseException {
+ if (bitLength != 1) {
+ throw new ParseException("Bit fields only support bitLength of 1");
+ }
+ writeBuffer.writeBit(logicalName, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterByte.java
new file mode 100644
index 0000000..b250e30
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterByte.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterByte implements DataWriter<Byte> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterByte(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Byte value, WithWriterArgs... writerArgs) throws ParseException {
+ if(bitLength != 8) {
+ throw new ParseException("Byte fields only support bitLength of 8");
+ }
+ writeBuffer.writeByte(logicalName, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterByteArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterByteArray.java
new file mode 100644
index 0000000..37a60c7
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterByteArray.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterByteArray implements DataWriter<byte[]> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterByteArray(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, byte[] value, WithWriterArgs... writerArgs) throws ParseException {
+ if (bitLength != 8) {
+ throw new ParseException("ByteArray fields only support bitLength of 8");
+ }
+ // TODO: Get a WirReaderArgs parameter for the number of bytes ...
+ writeBuffer.writeByteArray(logicalName, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterDouble.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterDouble.java
new file mode 100644
index 0000000..c201e53
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterDouble.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterDouble implements DataWriter<Double> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterDouble(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Double value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeDouble(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterFloat.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterFloat.java
new file mode 100644
index 0000000..70d598f
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterFloat.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.WithWriterArgs;
+import org.apache.plc4x.java.spi.generation.WriteBuffer;
+
+import java.util.Objects;
+
+public class DataWriterFloat implements DataWriter<Float> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterFloat(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Float value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeFloat(logicalName, bitLength, value);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedBigInteger.java
new file mode 100644
index 0000000..33aee9e
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedBigInteger.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.math.BigInteger;
+import java.util.Objects;
+
+public class DataWriterSignedBigInteger implements DataWriter<BigInteger> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterSignedBigInteger(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeBigInteger(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedByte.java
new file mode 100644
index 0000000..88c2c3f
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedByte.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterSignedByte implements DataWriter<Byte> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterSignedByte(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Byte value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeSignedByte(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedInt.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedInt.java
new file mode 100644
index 0000000..effd5be
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedInt.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterSignedInt implements DataWriter<Integer> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterSignedInt(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Integer value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeInt(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedLong.java
new file mode 100644
index 0000000..b0f8bd8
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedLong.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterSignedLong implements DataWriter<Long> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterSignedLong(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Long value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeLong(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedShort.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedShort.java
new file mode 100644
index 0000000..5bc64c1
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSignedShort.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterSignedShort implements DataWriter<Short> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterSignedShort(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Short value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeShort(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedBigInteger.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedBigInteger.java
new file mode 100644
index 0000000..a9ab701
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedBigInteger.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.math.BigInteger;
+import java.util.Objects;
+
+public class DataWriterUnsignedBigInteger implements DataWriter<BigInteger> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterUnsignedBigInteger(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, BigInteger value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeUnsignedBigInteger(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedByte.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedByte.java
new file mode 100644
index 0000000..c386c8e
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedByte.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterUnsignedByte implements DataWriter<Byte> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterUnsignedByte(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Byte value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeUnsignedByte(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedInt.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedInt.java
new file mode 100644
index 0000000..bbe8c24
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedInt.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterUnsignedInt implements DataWriter<Integer> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterUnsignedInt(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Integer value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeUnsignedInt(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedLong.java
new file mode 100644
index 0000000..3af0c82
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterUnsignedLong.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.plc4x.java.spi.codegen.io;
+
+import org.apache.plc4x.java.spi.generation.*;
+
+import java.util.Objects;
+
+public class DataWriterUnsignedLong implements DataWriter<Long> {
+
+ private final WriteBuffer writeBuffer;
+
+ public DataWriterUnsignedLong(WriteBuffer writeBuffer) {
+ this.writeBuffer = Objects.requireNonNull(writeBuffer);
+ }
+
+ @Override
+ public void write(String logicalName, int bitLength, Long value, WithWriterArgs... writerArgs) throws ParseException {
+ writeBuffer.writeUnsignedLong(logicalName, bitLength, value, writerArgs);
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
index f45f72a..85f27ca 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
@@ -275,19 +275,19 @@ public class WriteBufferByteBased implements WriteBuffer {
}
@Override
- public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
- if (bitsExponent != 8 || bitsMantissa != 23) {
+ public void writeFloat(String logicalName, int bitLength, float value, WithWriterArgs... writerArgs) throws ParseException {
+ if (bitLength != 32) {
throw new UnsupportedOperationException("Error writing float: Exponent and/or Mantissa non standard size");
}
- writeInt(logicalName, 1 + bitsExponent + bitsMantissa, Float.floatToRawIntBits(value));
+ writeInt(logicalName, bitLength, Float.floatToRawIntBits(value));
}
@Override
- public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
- if (bitsExponent != 11 || bitsMantissa != 52) {
+ public void writeDouble(String logicalName, int bitLength, double value, WithWriterArgs... writerArgs) throws ParseException {
+ if (bitLength != 64) {
throw new UnsupportedOperationException("Error writing double: Exponent and/or Mantissa non standard size");
}
- writeLong(logicalName, 1 + bitsExponent + bitsMantissa, Double.doubleToRawLongBits(value));
+ writeLong(logicalName, bitLength, Double.doubleToRawLongBits(value));
}
@Override
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
index 1779981..4db800e 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferJsonBased.java
@@ -207,20 +207,18 @@ public class WriteBufferJsonBased implements WriteBuffer, BufferCommons, AutoClo
}
@Override
- public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
+ public void writeFloat(String logicalName, int bitLength, float value, WithWriterArgs... writerArgs) throws ParseException {
final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
wrapIfNecessary(() -> {
- int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
writeAttr(sanitizedLogicalName, rwFloatKey, bitLength, writerArgs);
generator.writeNumberField(logicalName, value);
});
}
@Override
- public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
+ public void writeDouble(String logicalName, int bitLength, double value, WithWriterArgs... writerArgs) throws ParseException {
final String sanitizedLogicalName = sanitizeLogicalName(logicalName);
wrapIfNecessary(() -> {
- int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
writeAttr(sanitizedLogicalName, rwFloatKey, bitLength, writerArgs);
generator.writeNumberField(sanitizedLogicalName, value);
});
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
index de94548..d09858f 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
@@ -18,7 +18,6 @@
*/
package org.apache.plc4x.java.spi.generation;
-import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
@@ -172,15 +171,13 @@ public class WriteBufferXmlBased implements WriteBuffer, BufferCommons {
}
@Override
- public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
- int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
+ public void writeFloat(String logicalName, int bitLength, float value, WithWriterArgs... writerArgs) throws ParseException {
createAndAppend(logicalName, rwFloatKey, bitLength, Float.toString(value), writerArgs);
move(bitLength);
}
@Override
- public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa, WithWriterArgs... writerArgs) throws ParseException {
- int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
+ public void writeDouble(String logicalName, int bitLength, double value, WithWriterArgs... writerArgs) throws ParseException {
createAndAppend(logicalName, rwFloatKey, bitLength, Double.toString(value), writerArgs);
move(bitLength);
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java
index 83be2bf..3a675fc 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcLREAL.java
@@ -28,7 +28,6 @@ import org.apache.plc4x.java.spi.generation.WriteBuffer;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
public class PlcLREAL extends PlcIECValue<Double> {
@@ -266,7 +265,7 @@ public class PlcLREAL extends PlcIECValue<Double> {
@Override
public void serialize(WriteBuffer writeBuffer) throws ParseException {
- writeBuffer.writeDouble(getClass().getSimpleName(), value, 11, 52);
+ writeBuffer.writeDouble(getClass().getSimpleName(), 64, value);
}
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java
index 21f4a43..9032127 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/values/PlcREAL.java
@@ -25,7 +25,6 @@ import org.apache.plc4x.java.spi.generation.WriteBuffer;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
public class PlcREAL extends PlcIECValue<Float> {
@@ -257,7 +256,7 @@ public class PlcREAL extends PlcIECValue<Float> {
@Override
public void serialize(WriteBuffer writeBuffer) throws ParseException {
- writeBuffer.writeDouble(getClass().getSimpleName(), value, 8, 23);
+ writeBuffer.writeDouble(getClass().getSimpleName(), 32, value);
}
}
diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
index b62fb90..40050d3 100644
--- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec
+++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
@@ -448,10 +448,10 @@
// Floating point values
// -----------------------------------------
['IEC61131_REAL' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['IEC61131_LREAL' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
// -----------------------------------------
diff --git a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
index aac3cbe..eea1894 100644
--- a/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
+++ b/protocols/bacnetip/src/main/resources/protocols/bacnetip/bacnetip.mspec
@@ -348,10 +348,10 @@
[array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
]
['REAL' BACnetComplexTagReal [uint 3 'lengthValueType', uint 8 'extLength']
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['DOUBLE' BACnetComplexTagDouble [uint 3 'lengthValueType', uint 8 'extLength']
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
['OCTET_STRING' BACnetComplexTagOctetString [uint 32 'actualLength']
// TODO: The reader expects int but uint32 get's mapped to long so even uint32 would easily overflow...
@@ -561,10 +561,10 @@
[array int 8 'data' length '(lengthValueType == 5) ? extLength : lengthValueType']
]
['APPLICATION_TAGS','0x4' BACnetTagApplicationReal [uint 3 'lengthValueType', uint 8 'extLength']
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['APPLICATION_TAGS','0x5' BACnetTagApplicationDouble [uint 3 'lengthValueType', uint 8 'extLength']
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
['APPLICATION_TAGS','0x6' BACnetTagApplicationOctetString
]
diff --git a/protocols/canopen/src/main/resources/protocols/can/canopen.mspec b/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
index b613ad5..1f0bfab 100644
--- a/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
+++ b/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
@@ -324,10 +324,10 @@
[simple int 64 'value']
]
['REAL32' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['REAL64' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
['RECORD' List [int 32 'size']
[array int 8 'value' length 'size']
diff --git a/protocols/genericcan/src/main/resources/protocols/can/genericcan.mspec b/protocols/genericcan/src/main/resources/protocols/can/genericcan.mspec
index 26f491f..60f1b03 100644
--- a/protocols/genericcan/src/main/resources/protocols/can/genericcan.mspec
+++ b/protocols/genericcan/src/main/resources/protocols/can/genericcan.mspec
@@ -97,10 +97,10 @@
[simple int 64 'value']
]
['REAL32' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['REAL64' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
]
]
diff --git a/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec b/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
index 3788de8..f749916 100644
--- a/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
+++ b/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
@@ -836,7 +836,7 @@
[simple uint 16 'value']
]
['PDT_KNX_FLOAT' REAL
- [simple float 4.11 'value']
+ [simple float 16 'value' encoding='"KNXFloat"']
]
['PDT_DATE' Struct
[reserved uint 3 '0x00']
@@ -860,10 +860,10 @@
[simple uint 32 'value']
]
['PDT_FLOAT' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['PDT_DOUBLE' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
['PDT_CHAR_BLOCK' List
[array uint 8 'value' count '10']
diff --git a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
index 8f29eec..750dc76 100644
--- a/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
+++ b/protocols/modbus/src/main/resources/protocols/modbus/modbus.mspec
@@ -352,16 +352,16 @@
[array uint 64 'value' count 'numberOfValues']
]
['REAL','1' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['REAL' List
- [array float 8.23 'value' count 'numberOfValues']
+ [array float 32 'value' count 'numberOfValues']
]
['LREAL','1' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
['LREAL' List
- [array float 11.52 'value' count 'numberOfValues']
+ [array float 64 'value' count 'numberOfValues']
]
['CHAR','1' CHAR
[simple uint 8 'value']
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index af96a7e..9e35fa6 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -587,10 +587,10 @@
// Floating point values
// -----------------------------------------
['IEC61131_REAL' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['IEC61131_LREAL' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
// -----------------------------------------
diff --git a/protocols/simulated/src/main/resources/protocols/simulated/simulated.mspec b/protocols/simulated/src/main/resources/protocols/simulated/simulated.mspec
index a5d5bb5..7cd895a 100644
--- a/protocols/simulated/src/main/resources/protocols/simulated/simulated.mspec
+++ b/protocols/simulated/src/main/resources/protocols/simulated/simulated.mspec
@@ -104,16 +104,16 @@
[array uint 64 'value' count 'numberOfValues']
]
['REAL','1' REAL
- [simple float 8.23 'value']
+ [simple float 32 'value']
]
['REAL' List
- [array float 8.23 'value' count 'numberOfValues']
+ [array float 32 'value' count 'numberOfValues']
]
['LREAL','1' LREAL
- [simple float 11.52 'value']
+ [simple float 64 'value']
]
['LREAL' List
- [array float 11.52 'value' count 'numberOfValues']
+ [array float 64 'value' count 'numberOfValues']
]
['CHAR','1' CHAR
[simple uint 8 'value']