You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2021/10/22 16:59:51 UTC
[plc4x] 01/02: fix(plc4j/codgen): implement array type reading with
new readern
This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch feature/mspec-ng
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 90e40fd5c02b0384ccfa205cfb8e109bf56f6e1b
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Oct 22 18:23:04 2021 +0200
fix(plc4j/codgen): implement array type reading with new readern
---
.../resources/templates/java/io-template.java.ftlh | 122 ++-------------------
.../plc4x/java/spi/codegen/fields/FieldReader.java | 1 +
.../java/spi/codegen/fields/FieldReaderArray.java | 56 ++++++++--
.../spi/codegen/fields/FieldReaderFactory.java | 54 ++++++++-
4 files changed, 104 insertions(+), 129 deletions(-)
diff --git a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
index 8aeadd8..af61334 100644
--- a/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -148,6 +148,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
<#-- TODO: Port this -->
<#case "array">
<#assign arrayField = field.asArrayField().orElseThrow()>
+
<#if arrayField.type.isByteBased()>
// Byte Array field (${arrayField.name})
<#assign numberOfBytesExpression>
@@ -169,7 +170,6 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
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;
@@ -177,130 +177,22 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
<#-- 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>
- }
- }
+ Object ${arrayField.name}Object = readCountArrayField(${helper.getLanguageTypeNameForField(field)}.class, "${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
+ ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = (${helper.getLanguageTypeNameForField(field)}[]) ${arrayField.name}Object;
<#-- 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>
- }
+ Object ${arrayField.name}Object = readLengthArrayField(${helper.getLanguageTypeNameForField(field)}.class, "${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
+ ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = (${helper.getLanguageTypeNameForField(field)}[]) ${arrayField.name}Object;
<#-- 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]);
+ Object ${arrayField.name}Object = readTerminatedArrayField(${helper.getLanguageTypeNameForField(field)}.class, "${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)})));
+ ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = (${helper.getLanguageTypeNameForField(field)}[]) ${arrayField.name}Object;
</#if>
</#if>
- readBuffer.closeContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
</#if>
<#break>
<#case "assert">
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
index 382e3ef..86d43f3 100644
--- 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
@@ -25,6 +25,7 @@ import org.apache.plc4x.java.spi.generation.WithReaderArgs;
public interface FieldReader<T> extends FieldCommons {
+ // TODO: this is useless here as you always operate on the concrete instance
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/FieldReaderArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderArray.java
index 1724c62..251d305 100644
--- 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
@@ -18,31 +18,65 @@
*/
package org.apache.plc4x.java.spi.codegen.fields;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.NotImplementedException;
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;
+import org.apache.plc4x.java.spi.generation.WithReaderWriterArgs;
-public class FieldReaderArray<T> implements FieldReader<T> {
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Supplier;
- private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderArray.class);
+public class FieldReaderArray<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));
+ throw new NotImplementedException("use dedicated methods instead");
}
- public T[] readFieldCount(String logicalName, DataReader<T> dataReader, int count, WithReaderArgs... readerArgs) throws ParseException {
- return null;
+ public List<T> readFieldCount(String logicalName, DataReader<T> dataReader, long count, WithReaderArgs... readerArgs) throws ParseException {
+ if (count > Integer.MAX_VALUE) {
+ throw new ParseException("Array count of " + count + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
+ }
+ // Ensure we have the render as list argument present
+ readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
+ dataReader.pullContext(logicalName, readerArgs);
+ int itemCount = Math.max(0, (int) count);
+ List<T> result = new ArrayList<>(itemCount);
+ for (int curItem = 0; curItem < itemCount; curItem++) {
+ result.set(curItem, dataReader.read("", readerArgs));
+ }
+ dataReader.closeContext(logicalName, readerArgs);
+ return result;
}
- public T[] readFieldLength(String logicalName, DataReader<T> dataReader, int length, WithReaderArgs... readerArgs) throws ParseException {
- return null;
+ public List<T> readFieldLength(String logicalName, DataReader<T> dataReader, int length, WithReaderArgs... readerArgs) throws ParseException {
+ // Ensure we have the render as list argument present
+ readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
+ dataReader.pullContext(logicalName, readerArgs);
+ List<T> result = new LinkedList<>();
+ while (dataReader.getPos() < length) {
+ result.add(dataReader.read("", readerArgs));
+ }
+ dataReader.closeContext(logicalName, readerArgs);
+ return result;
}
- public T[] readFieldTerminated(String logicalName, DataReader<T> dataReader, T termination, WithReaderArgs... readerArgs) throws ParseException {
- return null;
+ public List<T> readFieldTerminated(String logicalName, DataReader<T> dataReader, Supplier<Boolean> termination, WithReaderArgs... readerArgs) throws ParseException {
+ // Ensure we have the render as list argument present
+ readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
+ dataReader.pullContext(logicalName, readerArgs);
+ List<T> result = new LinkedList<>();
+ while (!termination.get()) {
+ result.add(dataReader.read("", readerArgs));
+ }
+ dataReader.closeContext(logicalName, readerArgs);
+ return result;
}
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
index da87857..567a050 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldReaderFactory.java
@@ -22,14 +22,62 @@ 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 java.lang.reflect.Array;
+import java.util.List;
+import java.util.function.Supplier;
+
public class FieldReaderFactory {
public static <T> T readAbstractField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
return new FieldReaderAbstract<T>().readField(logicalName, dataReader, readerArgs);
}
- public static <T> T readArrayField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
- return new FieldReaderArray<T>().readField(logicalName, dataReader, readerArgs);
+ @Deprecated
+ @SuppressWarnings("unchecked")
+ public static <T> T[] readCountArrayField(Class<T> t, String logicalName, DataReader<T> dataReader, long count, WithReaderArgs... readerArgs) throws ParseException {
+ List<T> innerResult = readCountArrayField(logicalName, dataReader, count, readerArgs);
+ T[] result = (T[]) Array.newInstance(t, innerResult.size());
+ for (int curItem = 0; curItem < innerResult.size(); curItem++) {
+ result[curItem] = innerResult.get(curItem);
+ }
+ dataReader.closeContext(logicalName, readerArgs);
+ return result;
+ }
+
+ public static <T> List<T> readCountArrayField(String logicalName, DataReader<T> dataReader, long count, WithReaderArgs... readerArgs) throws ParseException {
+ return new FieldReaderArray<T>().readFieldCount(logicalName, dataReader, count, readerArgs);
+ }
+
+ @Deprecated
+ @SuppressWarnings("unchecked")
+ public static <T> T[] readLengthArrayField(Class<T> t, String logicalName, DataReader<T> dataReader, int length, WithReaderArgs... readerArgs) throws ParseException {
+ List<T> innerResult = readLengthArrayField(logicalName, dataReader, length, readerArgs);
+ T[] result = (T[]) Array.newInstance(t, innerResult.size());
+ for (int curItem = 0; curItem < innerResult.size(); curItem++) {
+ result[curItem] = innerResult.get(curItem);
+ }
+ dataReader.closeContext(logicalName, readerArgs);
+ return result;
+ }
+
+ public static <T> List<T> readLengthArrayField(String logicalName, DataReader<T> dataReader, int length, WithReaderArgs... readerArgs) throws ParseException {
+ return new FieldReaderArray<T>().readFieldLength(logicalName, dataReader, length, readerArgs);
+ }
+
+ @Deprecated
+ @SuppressWarnings("unchecked")
+ public static <T> T[] readTerminatedArrayField(Class<T> t, String logicalName, DataReader<T> dataReader, Supplier<Boolean> termination, WithReaderArgs... readerArgs) throws ParseException {
+ List<T> innerResult = readTerminatedArrayField(logicalName, dataReader, termination, readerArgs);
+ T[] result = (T[]) Array.newInstance(t, innerResult.size());
+ for (int curItem = 0; curItem < innerResult.size(); curItem++) {
+ result[curItem] = innerResult.get(curItem);
+ }
+ dataReader.closeContext(logicalName, readerArgs);
+ return result;
+ }
+
+ public static <T> List<T> readTerminatedArrayField(String logicalName, DataReader<T> dataReader, Supplier<Boolean> termination, WithReaderArgs... readerArgs) throws ParseException {
+ return new FieldReaderArray<T>().readFieldTerminated(logicalName, dataReader, termination, readerArgs);
}
public static <T> T readAssertField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
@@ -69,7 +117,7 @@ public class FieldReaderFactory {
}
public static <T> T readSimpleField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
- return new FieldReaderSimple<T>().readField(logicalName,dataReader,readerArgs);
+ return new FieldReaderSimple<T>().readField(logicalName, dataReader, readerArgs);
}
public static <T> T readUnknownField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {