diff --git a/migration-tools/modules/migration-tools-commons-tests/src/main/java/org/apache/ignite/migrationtools/tests/models/NestedPojoWithAnnotations.java b/migration-tools/modules/migration-tools-commons-tests/src/main/java/org/apache/ignite/migrationtools/tests/models/NestedPojoWithAnnotations.java new file mode 100644 index 000000000000..beb074b2d170 --- /dev/null +++ b/migration-tools/modules/migration-tools-commons-tests/src/main/java/org/apache/ignite/migrationtools/tests/models/NestedPojoWithAnnotations.java @@ -0,0 +1,61 @@ +/* + * 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.ignite.migrationtools.tests.models; + +import java.util.Objects; +import org.apache.ignite.cache.query.annotations.QuerySqlField; + +/** NestedPojoWithAnnotations. */ +public class NestedPojoWithAnnotations { + @QuerySqlField + private long id; + + @QuerySqlField + private SimplePojo nestedPojo; + + public NestedPojoWithAnnotations() { + // Intentionally left blank. + } + + public NestedPojoWithAnnotations(long id, SimplePojo nestedObj) { + this.id = id; + this.nestedPojo = nestedObj; + } + + public long getId() { + return id; + } + + public SimplePojo getNestedPojo() { + return nestedPojo; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof NestedPojoWithAnnotations)) { + return false; + } + NestedPojoWithAnnotations that = (NestedPojoWithAnnotations) o; + return id == that.id && Objects.equals(nestedPojo, that.nestedPojo); + } + + @Override + public int hashCode() { + return Objects.hash(id, nestedPojo); + } +} diff --git a/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/sql/SqlDdlGenerator.java b/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/sql/SqlDdlGenerator.java index 821b0d57b5b3..f75e855251aa 100644 --- a/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/sql/SqlDdlGenerator.java +++ b/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/sql/SqlDdlGenerator.java @@ -388,6 +388,9 @@ private QueryEntityEvaluation populateQueryEntity(QueryEntity qe, boolean allowE } } + // Tracks whether this QE maps a POJO on either Key/Value. + boolean mapsPojo = false; + // Go over existing fields in the QE to they are correct and there are not silly nulls. { // AI2 may define primitive field types, however, they still mark them as nullable somehow. @@ -430,6 +433,28 @@ private QueryEntityEvaluation populateQueryEntity(QueryEntity qe, boolean allowE // Mark keyFields as not nullable. qe.getNotNullFields().addAll(qe.getKeyFields()); + + // We also want to remove fields non-compliant with AI3 so that they are handled in the extra fields. + for (var e : qe.getFields().entrySet()) { + String fieldType = ClassnameUtils.ensureWrapper(e.getValue()); + + boolean isNativelySupportedType; + try { + Class type = ClassUtils.getClass(this.clientClassLoader, fieldType); + isNativelySupportedType = TypeInspector.isPrimitiveType(type); + } catch (ClassNotFoundException ignored) { + // All natively supported types should be in the classpath. + // Some enums might still slip throught. + isNativelySupportedType = false; + } + + // Remove from the field list, we will need to map it in the extra fields. + if (!isNativelySupportedType) { + mapsPojo = true; + qe.getFields().remove(e.getKey()); + qe.getKeyFields().remove(e.getKey()); + } + } } @Nullable Map keyFieldToColumnMap; @@ -558,7 +583,7 @@ private Entry( } // Empty field lists means that the class for the type is not available on the classpath so it must be a pojo. - boolean mapsPojo = keyFields.isEmpty() || valFields.isEmpty(); + mapsPojo = mapsPojo || keyFields.isEmpty() || valFields.isEmpty(); // Process key fields { @@ -583,7 +608,7 @@ private Entry( // Process value fields { - if (valFields.size() == 1) { + if (valFields.size() == 1 && !mapsPojo) { InspectedField inspectedField = valFields.get(0); String columnName = valFieldToColumnMap.get(inspectedField); diff --git a/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/types/TypeInspector.java b/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/types/TypeInspector.java index 9dc4630c5a8f..8d1927953650 100644 --- a/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/types/TypeInspector.java +++ b/migration-tools/modules/migration-tools-commons/src/main/java/org/apache/ignite/migrationtools/types/TypeInspector.java @@ -133,7 +133,13 @@ public static List inspectType(Class type) { } } - private static boolean isPrimitiveType(Class type) { + /** + * Whether the provided class, or it's derivatives, is natively supported. + * + * @param type Type. + * @return True or false. + */ + public static boolean isPrimitiveType(Class type) { return type.isEnum() || Mapper.nativelySupported(type) || COL_TYPE_REF.containsKey(type); } diff --git a/migration-tools/modules/migration-tools-commons/src/test/java/org/apache/ignite/migrationtools/sql/sql/SqlDdlGeneratorTest.java b/migration-tools/modules/migration-tools-commons/src/test/java/org/apache/ignite/migrationtools/sql/sql/SqlDdlGeneratorTest.java index 588fbbaef6e6..440c250baa57 100644 --- a/migration-tools/modules/migration-tools-commons/src/test/java/org/apache/ignite/migrationtools/sql/sql/SqlDdlGeneratorTest.java +++ b/migration-tools/modules/migration-tools-commons/src/test/java/org/apache/ignite/migrationtools/sql/sql/SqlDdlGeneratorTest.java @@ -64,6 +64,7 @@ import org.apache.ignite.migrationtools.tests.models.ComplexKeyIntStr; import org.apache.ignite.migrationtools.tests.models.IdentifiedPojo; import org.apache.ignite.migrationtools.tests.models.InterceptingFieldsModel; +import org.apache.ignite.migrationtools.tests.models.NestedPojoWithAnnotations; import org.apache.ignite.migrationtools.tests.models.SimplePojo; import org.apache.ignite3.catalog.ColumnSorted; import org.apache.ignite3.catalog.definitions.ColumnDefinition; @@ -347,6 +348,28 @@ void testTableDefWithComplexKeyAndSimplePojo( ); } + @ParameterizedTest + @MethodSource("provideCacheConfigSupplier") + void testTableDefWithNestedPojoWithAnnotations( + BiFunction, Class, CacheConfiguration> cacheConfigSupplier, + boolean allowExtraFields + ) { + var cacheCfg = cacheConfigSupplier.apply(String.class, NestedPojoWithAnnotations.class); + testCacheConfig( + cacheCfg, + allowExtraFields, + List.of( + primaryKey("KEY", "VARCHAR"), + nonKey("id", "BIGINT", false) + ), + entry(String.class.getName(), NestedPojoWithAnnotations.class.getName()), + emptyMap(), + Map.ofEntries( + entry("id", "id") + ) + ); + } + @ParameterizedTest @MethodSource("provideCacheConfigSupplier") void testTableDefWithOrganizationPojo(