ATLAS-2332: support for attributes having nested collection datatype
Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/38159334 Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/38159334 Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/38159334 Branch: refs/heads/master Commit: 38159334645dfcd8b3c948aea18e71cc0d7dfcbc Parents: 1ff791c Author: Madhan Neethiraj <mad...@apache.org> Authored: Wed Jan 3 19:14:54 2018 -0800 Committer: Madhan Neethiraj <mad...@apache.org> Committed: Thu Jan 4 14:15:43 2018 -0800 ---------------------------------------------------------------------- .../graphdb/janus/AtlasJanusGraphDatabase.java | 8 +- .../janus/serializer/StringListSerializer.java | 54 ------- .../test/java/org/apache/atlas/TestUtilsV2.java | 145 +++++++++++++++++++ .../atlas/repository/graph/GraphHelper.java | 2 +- .../store/graph/v1/EntityGraphMapper.java | 8 +- .../store/graph/v1/EntityGraphRetriever.java | 4 +- .../store/graph/AtlasTypeDefGraphStoreTest.java | 15 ++ .../store/graph/v1/AtlasEntityStoreV1Test.java | 14 +- 8 files changed, 188 insertions(+), 62 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphDatabase.java ---------------------------------------------------------------------- diff --git a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphDatabase.java b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphDatabase.java index 019cd22..f91226b 100644 --- a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphDatabase.java +++ b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphDatabase.java @@ -24,12 +24,16 @@ import org.apache.atlas.repository.graphdb.AtlasGraph; import org.apache.atlas.repository.graphdb.GraphDatabase; import org.apache.atlas.repository.graphdb.janus.serializer.BigDecimalSerializer; import org.apache.atlas.repository.graphdb.janus.serializer.BigIntegerSerializer; -import org.apache.atlas.repository.graphdb.janus.serializer.StringListSerializer; import org.apache.atlas.repository.graphdb.janus.serializer.TypeCategorySerializer; import org.apache.atlas.runner.LocalSolrRunner; import org.apache.atlas.typesystem.types.DataTypes.TypeCategory; import org.apache.commons.configuration.Configuration; import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; +import org.janusgraph.graphdb.database.serialize.attribute.SerializableSerializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.janusgraph.core.JanusGraphFactory; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.JanusGraphFactory; import org.janusgraph.core.schema.JanusGraphManagement; @@ -81,7 +85,7 @@ public class AtlasJanusGraphDatabase implements GraphDatabase<AtlasJanusVertex, //not ideal, but avoids making large changes to Atlas janusConfig.addProperty("attributes.custom.attribute2.attribute-class", ArrayList.class.getName()); - janusConfig.addProperty("attributes.custom.attribute2.serializer-class", StringListSerializer.class.getName()); + janusConfig.addProperty("attributes.custom.attribute2.serializer-class", SerializableSerializer.class.getName()); janusConfig.addProperty("attributes.custom.attribute3.attribute-class", BigInteger.class.getName()); janusConfig.addProperty("attributes.custom.attribute3.serializer-class", BigIntegerSerializer.class.getName()); http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/serializer/StringListSerializer.java ---------------------------------------------------------------------- diff --git a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/serializer/StringListSerializer.java b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/serializer/StringListSerializer.java deleted file mode 100644 index fa6f5fd..0000000 --- a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/serializer/StringListSerializer.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * 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.atlas.repository.graphdb.janus.serializer; - -import java.util.ArrayList; -import java.util.List; - -import org.janusgraph.core.attribute.AttributeSerializer; -import org.janusgraph.diskstorage.ScanBuffer; -import org.janusgraph.diskstorage.WriteBuffer; -import org.janusgraph.graphdb.database.idhandling.VariableLong; -import org.janusgraph.graphdb.database.serialize.attribute.StringSerializer; - -/** - * Serializer for String lists. - */ -public class StringListSerializer implements AttributeSerializer<List<String>> { - - private final StringSerializer stringSerializer = new StringSerializer(); - - @Override - public List<String> read(ScanBuffer buffer) { - int length = (int)VariableLong.readPositive(buffer); - List<String> result = new ArrayList<String>(length); - for(int i = 0; i < length; i++) { - result.add(stringSerializer.read(buffer)); - } - return result; - } - - @Override - public void write(WriteBuffer buffer, List<String> attributes) { - VariableLong.writePositive(buffer, attributes.size()); - for(String attr : attributes) { - stringSerializer.write(buffer, attr); - } - } - -} http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/intg/src/test/java/org/apache/atlas/TestUtilsV2.java ---------------------------------------------------------------------- diff --git a/intg/src/test/java/org/apache/atlas/TestUtilsV2.java b/intg/src/test/java/org/apache/atlas/TestUtilsV2.java index bbccf77..94242ad 100755 --- a/intg/src/test/java/org/apache/atlas/TestUtilsV2.java +++ b/intg/src/test/java/org/apache/atlas/TestUtilsV2.java @@ -541,6 +541,7 @@ public final class TestUtilsV2 { public static final String SERDE_TYPE = "serdeType"; public static final String COLUMNS_MAP = "columnsMap"; public static final String COLUMNS_ATTR_NAME = "columns"; + public static final String ENTITY_TYPE_WITH_NESTED_COLLECTION_ATTR = "entity_with_nested_collection_attr"; public static final String NAME = "name"; @@ -832,6 +833,150 @@ public final class TestUtilsV2 { return ret; } + public static AtlasTypesDef defineTypeWithNestedCollectionAttributes() { + AtlasEntityDef nestedCollectionAttributesEntityType = + AtlasTypeUtil.createClassTypeDef(ENTITY_TYPE_WITH_NESTED_COLLECTION_ATTR, ENTITY_TYPE_WITH_NESTED_COLLECTION_ATTR + "_description", null, + AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"), + + new AtlasAttributeDef("mapOfArrayOfStrings", "map<string,array<string>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfArrayOfBooleans", "map<string,array<boolean>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfArrayOfInts", "map<string,array<int>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfArrayOfFloats", "map<string,array<float>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfArrayOfDates", "map<string,array<date>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + + new AtlasAttributeDef("mapOfMapOfStrings", "map<string,map<string,string>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfMapOfBooleans", "map<string,map<string,boolean>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfMapOfInts", "map<string,map<string,int>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfMapOfFloats", "map<string,map<string,float>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("mapOfMapOfDates", "map<string,map<string,date>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + + new AtlasAttributeDef("arrayOfArrayOfStrings", "array<array<string>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfArrayOfBooleans", "array<array<boolean>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfArrayOfInts", "array<array<int>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfArrayOfFloats", "array<array<float>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfArrayOfDates", "array<array<date>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + + new AtlasAttributeDef("arrayOfMapOfStrings", "array<map<string,string>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfMapOfBooleans", "array<map<string,boolean>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfMapOfInts", "array<map<string,int>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfMapOfFloats", "array<map<string,float>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()), + new AtlasAttributeDef("arrayOfMapOfDates", "array<map<string,date>>", false, + AtlasAttributeDef.Cardinality.SINGLE, 1, 1, + false, false, + Collections.<AtlasConstraintDef>emptyList()) + ); + + AtlasTypesDef ret = AtlasTypeUtil.getTypesDef(Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList(), + Arrays.asList(nestedCollectionAttributesEntityType)); + + populateSystemAttributes(ret); + + return ret; + } + + public static AtlasEntityWithExtInfo createNestedCollectionAttrEntity() { + AtlasEntity entity = new AtlasEntity(ENTITY_TYPE_WITH_NESTED_COLLECTION_ATTR); + + String[] arrayOfStrings = new String[] { "one", "two", "three" }; + boolean[] arrayOfBooleans = new boolean[] { false, true }; + int[] arrayOfInts = new int[] { 1, 2, 3 }; + float[] arrayOfFloats = new float[] { 1.1f, 2.2f, 3.3f }; + Date[] arrayOfDates = new Date[] { new Date() }; + + Map<String, String> mapOfStrings = Collections.singletonMap("one", "one"); + Map<String, Boolean> mapOfBooleans = Collections.singletonMap("one", true); + Map<String, Integer> mapOfInts = Collections.singletonMap("one", 1); + Map<String, Float> mapOfFloats = Collections.singletonMap("one", 1.1f); + Map<String, Date> mapOfDates = Collections.singletonMap("now", new Date()); + + entity.setAttribute("name", randomString() + "_" + System.currentTimeMillis()); + + entity.setAttribute("mapOfArrayOfStrings", Collections.singletonMap("one", arrayOfStrings)); + entity.setAttribute("mapOfArrayOfBooleans", Collections.singletonMap("one", arrayOfBooleans)); + entity.setAttribute("mapOfArrayOfInts", Collections.singletonMap("one", arrayOfInts)); + entity.setAttribute("mapOfArrayOfFloats", Collections.singletonMap("one", arrayOfFloats)); + entity.setAttribute("mapOfArrayOfDates", Collections.singletonMap("one", arrayOfDates)); + + entity.setAttribute("mapOfMapOfStrings", Collections.singletonMap("one", mapOfStrings)); + entity.setAttribute("mapOfMapOfBooleans", Collections.singletonMap("one", mapOfBooleans)); + entity.setAttribute("mapOfMapOfInts", Collections.singletonMap("one", mapOfInts)); + entity.setAttribute("mapOfMapOfFloats", Collections.singletonMap("one", mapOfFloats)); + entity.setAttribute("mapOfMapOfDates", Collections.singletonMap("one", mapOfDates)); + + entity.setAttribute("arrayOfArrayOfStrings", Collections.singletonList(arrayOfStrings)); + entity.setAttribute("arrayOfArrayOfBooleans", Collections.singletonList(arrayOfBooleans)); + entity.setAttribute("arrayOfArrayOfInts", Collections.singletonList(arrayOfInts)); + entity.setAttribute("arrayOfArrayOfFloats", Collections.singletonList(arrayOfFloats)); + entity.setAttribute("arrayOfArrayOfDates", Collections.singletonList(arrayOfDates)); + + entity.setAttribute("arrayOfMapOfStrings", Collections.singletonList(mapOfStrings)); + entity.setAttribute("arrayOfMapOfBooleans", Collections.singletonList(mapOfBooleans)); + entity.setAttribute("arrayOfMapOfInts", Collections.singletonList(mapOfInts)); + entity.setAttribute("arrayOfMapOfFloats", Collections.singletonList(mapOfFloats)); + entity.setAttribute("arrayOfMapOfDates", Collections.singletonList(mapOfDates)); + + return new AtlasEntityWithExtInfo(entity); + } + public static final String randomString() { return RandomStringUtils.randomAlphanumeric(10); } http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java index 3e60243..4da74b9 100755 --- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java +++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java @@ -1070,7 +1070,7 @@ public final class GraphHelper { if (AtlasGraphUtilsV1.isReference(elementType)) { return instanceVertex.getProperty(vertexPropertyName, AtlasEdge.class); } else { - return instanceVertex.getProperty(vertexPropertyName, Object.class).toString(); + return instanceVertex.getProperty(vertexPropertyName, Object.class); } } http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java index f6a15b6..c6aa98a 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java @@ -918,6 +918,8 @@ public class EntityGraphMapper { switch(ctx.getAttrType().getTypeCategory()) { case PRIMITIVE: case ENUM: + case MAP: + case ARRAY: return ctx.getValue(); case STRUCT: @@ -928,8 +930,6 @@ public class EntityGraphMapper { ctx.setElementType(instanceType); return mapObjectIdValueUsingRelationship(ctx, context); - case MAP: - case ARRAY: default: throw new AtlasBaseException(AtlasErrorCode.TYPE_CATEGORY_INVALID, ctx.getAttrType().getTypeCategory().name()); } @@ -1025,6 +1025,10 @@ public class EntityGraphMapper { public static Object getMapValueProperty(AtlasType elementType, AtlasVertex vertex, String vertexPropertyName) { if (AtlasGraphUtilsV1.isReference(elementType)) { return vertex.getProperty(vertexPropertyName, AtlasEdge.class); + } else if (elementType instanceof AtlasArrayType) { + return vertex.getProperty(vertexPropertyName, List.class); + } else if (elementType instanceof AtlasMapType) { + return vertex.getProperty(vertexPropertyName, Map.class); } else { return vertex.getProperty(vertexPropertyName, String.class).toString(); http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java index 706e737..e7cd51a 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java @@ -505,11 +505,11 @@ public final class EntityGraphRetriever { switch (arrayElement.getTypeCategory()) { case PRIMITIVE: case ENUM: + case ARRAY: + case MAP: ret = value; break; - case ARRAY: - case MAP: case CLASSIFICATION: break; http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java index e104722..2fc8015 100644 --- a/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java @@ -333,6 +333,21 @@ public class AtlasTypeDefGraphStoreTest { } } + @Test(dependsOnMethods = "testGet") + public void testCreateWithNestedContainerAttributes() { + AtlasTypesDef typesDef = TestUtilsV2.defineTypeWithNestedCollectionAttributes(); + + try { + AtlasTypesDef createdTypes = typeDefStore.createTypesDef(typesDef); + assertEquals(typesDef.getEnumDefs(), createdTypes.getEnumDefs(), "Data integrity issue while persisting"); + assertEquals(typesDef.getStructDefs(), createdTypes.getStructDefs(), "Data integrity issue while persisting"); + assertEquals(typesDef.getClassificationDefs(), createdTypes.getClassificationDefs(), "Data integrity issue while persisting"); + assertEquals(typesDef.getEntityDefs(), createdTypes.getEntityDefs(), "Data integrity issue while persisting"); + } catch (AtlasBaseException e) { + fail("creation of type with nested-container attributes should've succeeded"); + } + } + @Test(enabled = false) public void testCreateWithInvalidAttributes(){ } http://git-wip-us.apache.org/repos/asf/atlas/blob/38159334/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java index 1f8b9fd..f4b7053 100644 --- a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java @@ -100,6 +100,7 @@ public class AtlasEntityStoreV1Test { private AtlasEntitiesWithExtInfo deptEntity; private AtlasEntityWithExtInfo dbEntity; private AtlasEntityWithExtInfo tblEntity; + private AtlasEntityWithExtInfo nestedCollectionAttrEntity; private AtlasEntityWithExtInfo primitiveEntity; AtlasEntityChangeNotifier mockChangeNotifier = mock(AtlasEntityChangeNotifier.class); @@ -115,7 +116,8 @@ public class AtlasEntityStoreV1Test { new GraphBackedSearchIndexer(typeRegistry); AtlasTypesDef[] testTypesDefs = new AtlasTypesDef[] { TestUtilsV2.defineDeptEmployeeTypes(), - TestUtilsV2.defineHiveTypes() + TestUtilsV2.defineHiveTypes(), + TestUtilsV2.defineTypeWithNestedCollectionAttributes(), }; for (AtlasTypesDef typesDef : testTypesDefs) { @@ -130,6 +132,8 @@ public class AtlasEntityStoreV1Test { dbEntity = TestUtilsV2.createDBEntityV2(); tblEntity = TestUtilsV2.createTableEntityV2(dbEntity.getEntity()); + nestedCollectionAttrEntity = TestUtilsV2.createNestedCollectionAttrEntity(); + AtlasTypesDef typesDef11 = new AtlasTypesDef(); List primitiveEntityDef = new ArrayList<AtlasEntityDef>(); primitiveEntityDef.add(TestUtilsV2.createPrimitiveEntityDef()); @@ -229,6 +233,14 @@ public class AtlasEntityStoreV1Test { AtlasEntityHeader tableEntity = tableCreationResponse.getFirstCreatedEntityByTypeName(TABLE_TYPE); validateEntity(tblEntity, getEntityFromStore(tableEntity)); + + //Create nested-collection attribute entity + init(); + EntityMutationResponse entityMutationResponse = entityStore.createOrUpdate(new AtlasEntityStream(nestedCollectionAttrEntity), false); + validateMutationResponse(entityMutationResponse, EntityOperation.CREATE, 1); + + AtlasEntityHeader createdEntity = entityMutationResponse.getFirstCreatedEntityByTypeName(TestUtilsV2.ENTITY_TYPE_WITH_NESTED_COLLECTION_ATTR); + validateEntity(nestedCollectionAttrEntity, getEntityFromStore(createdEntity)); } @Test(dependsOnMethods = "testCreate")