| /** |
| * 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.typesystem.types; |
| |
| import java.util.HashSet; |
| |
| import org.apache.atlas.typesystem.IReferenceableInstance; |
| import org.apache.atlas.typesystem.ITypedReferenceableInstance; |
| import org.apache.atlas.typesystem.ITypedStruct; |
| import org.apache.atlas.typesystem.TypesDef; |
| import org.apache.atlas.typesystem.types.AttributeDefinition; |
| import org.apache.atlas.typesystem.types.ClassType; |
| import org.apache.atlas.typesystem.types.EnumTypeDefinition; |
| import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition; |
| import org.apache.atlas.typesystem.types.Multiplicity; |
| import org.apache.atlas.typesystem.types.StructTypeDefinition; |
| import org.apache.atlas.typesystem.types.TraitType; |
| import org.apache.atlas.typesystem.types.TypeSystem; |
| import org.apache.atlas.typesystem.types.utils.TypesUtil; |
| import org.testng.Assert; |
| import org.testng.annotations.BeforeTest; |
| import org.testng.annotations.Test; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| |
| |
| /** |
| * Unit test for {@link FieldMapping} |
| * |
| */ |
| public class FieldMappingTest { |
| |
| @BeforeTest |
| public void beforeTest() throws Exception { |
| TypeSystem typeSystem = TypeSystem.getInstance(); |
| typeSystem.reset(); |
| } |
| |
| @Test |
| public void testOutputReferenceableInstance() throws Exception { |
| // ATLAS-645: verify that FieldMapping.output(IReferenceableInstance) |
| // does not infinitely recurse when ITypedReferenceableInstance's reference each other. |
| HierarchicalTypeDefinition<ClassType> valueDef = TypesUtil.createClassTypeDef("Value", |
| ImmutableSet.<String>of(), |
| new AttributeDefinition("owner", "Owner", Multiplicity.OPTIONAL, false, null)); |
| |
| // Define class type with reference, where the value is a class reference to Value. |
| HierarchicalTypeDefinition<ClassType> ownerDef = TypesUtil.createClassTypeDef("Owner", |
| ImmutableSet.<String>of(), |
| new AttributeDefinition("value", "Value", Multiplicity.OPTIONAL, false, null)); |
| TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), |
| ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), |
| ImmutableList.of(ownerDef, valueDef)); |
| |
| TypeSystem typeSystem = TypeSystem.getInstance(); |
| typeSystem.defineTypes(typesDef); |
| ClassType ownerType = typeSystem.getDataType(ClassType.class, "Owner"); |
| |
| // Prior to fix for ATLAS-645, this call would throw a StackOverflowError |
| try { |
| ownerType.toString(); |
| } |
| catch (StackOverflowError e) { |
| Assert.fail("Infinite recursion in ClassType.toString() caused StackOverflowError"); |
| } |
| |
| ClassType valueType = typeSystem.getDataType(ClassType.class, "Value"); |
| |
| // Create instances of Owner and Value that reference each other. |
| ITypedReferenceableInstance ownerInstance = ownerType.createInstance(); |
| ITypedReferenceableInstance valueInstance = valueType.createInstance(); |
| // Set Owner.value reference to Value instance. |
| ownerInstance.set("value", valueInstance); |
| // Set Value.owner reference on Owner instance. |
| valueInstance.set("owner", ownerInstance); |
| |
| // Prior to fix for ATLAS-645, this call would throw a StackOverflowError |
| try { |
| ownerInstance.fieldMapping().output(ownerInstance, new StringBuilder(), "", new HashSet<IReferenceableInstance>()); |
| } |
| catch (StackOverflowError e) { |
| Assert.fail("Infinite recursion in FieldMapping.output() caused StackOverflowError"); |
| } |
| } |
| |
| @Test |
| public void testOutputStruct() throws Exception { |
| // ATLAS-645: verify that FieldMapping.output(IStruct) does not infinitely recurse |
| // when an IStruct and ITypedReferenceableInstance reference each other. |
| HierarchicalTypeDefinition<ClassType> valueDef = TypesUtil.createClassTypeDef("Value", |
| ImmutableSet.<String>of(), |
| new AttributeDefinition("owner", "Owner", Multiplicity.OPTIONAL, false, null)); |
| |
| |
| // Define struct type with reference, where the value is a class reference to Value. |
| StructTypeDefinition ownerDef = TypesUtil.createStructTypeDef("Owner", |
| new AttributeDefinition("value", "Value", Multiplicity.OPTIONAL, false, null)); |
| |
| TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), |
| ImmutableList.of(ownerDef), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), |
| ImmutableList.of(valueDef)); |
| |
| TypeSystem typeSystem = TypeSystem.getInstance(); |
| typeSystem.reset(); |
| typeSystem.defineTypes(typesDef); |
| StructType ownerType = typeSystem.getDataType(StructType.class, "Owner"); |
| ClassType valueType = typeSystem.getDataType(ClassType.class, "Value"); |
| |
| // Prior to fix for ATLAS-645, this call would throw a StackOverflowError |
| try { |
| ownerType.toString(); |
| } |
| catch (StackOverflowError e) { |
| Assert.fail("Infinite recursion in StructType.toString() caused StackOverflowError"); |
| } |
| |
| |
| // Create instances of Owner and Value that reference each other. |
| ITypedStruct ownerInstance = ownerType.createInstance(); |
| ITypedReferenceableInstance valueInstance = valueType.createInstance(); |
| // Set Owner.value reference to Value instance. |
| ownerInstance.set("value", valueInstance); |
| // Set Value.owner reference on Owner instance. |
| valueInstance.set("owner", ownerInstance); |
| |
| // Prior to fix for ATLAS-645, this call would throw a StackOverflowError |
| try { |
| ownerInstance.fieldMapping().output(ownerInstance, new StringBuilder(), "", null); |
| } |
| catch (StackOverflowError e) { |
| Assert.fail("Infinite recursion in FieldMapping.output() caused StackOverflowError"); |
| } |
| |
| } |
| } |