roaster icon indicating copy to clipboard operation
roaster copied to clipboard

Qualified name of inner classes missing the enclosing type

Open thorstengross opened this issue 3 years ago • 1 comments

If you reference an inner class (or interface) in the extends clause / implements clause / field / return type of method / parameter of method, the parent types are missing. I provided a small example:

import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.JavaInterfaceSource;
import org.jboss.forge.roaster.model.source.JavaSource;
import org.junit.jupiter.api.Test;

public class InnerClassesTest {

	private String testClass = """
			package alpha.beta.gamma;

				public class Foo {

					public class Bar extends Bar2 implements BarInterface {
						
						private Huu h;
					
						public Huu getHuu(Huu huu) throws BarException {return null;}

						public class Huu {

						}
					}
					
					public class Bar2 {}
					
					public interface BarInterface {}
					
				}

			""";

	@Test
	public void test() {
		JavaClassSource foo = (JavaClassSource) Roaster.parse(JavaSource.class, testClass);
		JavaClassSource bar = (JavaClassSource) foo.getNestedTypes().get(0);
		JavaClassSource bar2 = (JavaClassSource) foo.getNestedTypes().get(1);
		JavaInterfaceSource bar2Interface = (JavaInterfaceSource) foo.getNestedTypes().get(2);	
		JavaClassSource huu = (JavaClassSource) bar.getNestedTypes().get(0);
		
		System.out.println(bar.getSuperType()+" should be "+bar2.getQualifiedName());		
		System.out.println(bar.getInterfaces().get(0)+" should be "+bar2Interface.getQualifiedName());	
		System.out.println(bar.getFields().get(0).getType().getQualifiedNameWithGenerics() +" should be "+huu.getQualifiedName());
		System.out.println(bar.getMethods().get(0).getReturnType().getQualifiedNameWithGenerics()+" should be "+huu.getQualifiedName());
		System.out.println(bar.getMethods().get(0).getParameters().get(0).getType().getQualifiedNameWithGenerics()+" should be "+huu.getQualifiedName());
		System.out.println(bar.getMethods().get(0).getParameters().get(0).getType().getQualifiedNameWithGenerics()+" should be "+huu.getQualifiedName());
	}
}

Produced output:

alpha.beta.gamma.Bar2 should be alpha.beta.gamma.Foo$Bar2
alpha.beta.gamma.BarInterface should be alpha.beta.gamma.Foo$BarInterface
alpha.beta.gamma.Huu should be alpha.beta.gamma.Foo$Bar$Huu
alpha.beta.gamma.Huu should be alpha.beta.gamma.Foo$Bar$Huu
alpha.beta.gamma.Huu should be alpha.beta.gamma.Foo$Bar$Huu
alpha.beta.gamma.Huu should be alpha.beta.gamma.Foo$Bar$Huu

thorstengross avatar Nov 14 '21 15:11 thorstengross

Here is a test using assertions based on your report:

package org.jboss.forge.test.roaster.model;

import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.JavaInterfaceSource;
import org.jboss.forge.roaster.model.source.JavaSource;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

public class InnerClassesTest
{

   private static final String CONTENTS =
            "package alpha.beta.gamma;"
                     + "public class Outer {"
                     + "   public class InnerExtendsClass extends InnerClass implements InnerInterface {"
                     + "      private InnerInnerExtendsClass h;"
                     + "      public InnerInnerExtendsClass getInnerInnerExtendsClass(InnerInnerExtendsClass huu) throws Exception {return null;}"
                     + "      public class InnerInnerExtendsClass {}"
                     + "   }"
                     + "   public class InnerClass {}"
                     + "   public interface InnerInterface {}"
                     + "}";
   private static JavaClassSource innerExtendsClass;
   private static JavaClassSource innerClass;
   private static JavaInterfaceSource innerInterface;
   private static JavaClassSource innerInnerExtendsClass;

   @BeforeAll
   static void setUp()
   {
      JavaClassSource outer = Roaster.parse(JavaClassSource.class, CONTENTS);
      List<JavaSource<?>> nestedTypes = outer.getNestedTypes();
      innerExtendsClass = (JavaClassSource) nestedTypes.get(0);
      innerClass = (JavaClassSource) nestedTypes.get(1);
      innerInterface = (JavaInterfaceSource) nestedTypes.get(2);
      innerInnerExtendsClass = (JavaClassSource) innerExtendsClass.getNestedTypes().get(0);
   }

   @Test
   void test_super_type_should_match_qualified_name()
   {
      assertThat(innerExtendsClass.getSuperType()).isEqualTo(innerClass.getQualifiedName());
   }

   @Test
   void test_interface_should_match_qualified_name()
   {
      assertThat(innerExtendsClass.getInterfaces().get(0)).isEqualTo(innerInterface.getQualifiedName());
   }

   @Test
   void test_field_type_should_match_qualified_name() {
      assertThat(innerExtendsClass.getFields().get(0).getType().getQualifiedNameWithGenerics()).isEqualTo(
               innerInnerExtendsClass.getQualifiedName());
   }

   @Test
   void test_method_return_type_should_match_qualified_name() {
      assertThat(innerExtendsClass.getMethods().get(0).getReturnType().getQualifiedNameWithGenerics())
               .isEqualTo(innerInnerExtendsClass.getQualifiedName());
   }

   @Test
   void test_method_parameter_type_should_match_qualified_name() {
      assertThat(innerExtendsClass.getMethods().get(0).getParameters().get(0).getType().getQualifiedNameWithGenerics())
               .isEqualTo(innerInnerExtendsClass.getQualifiedName());
   }

}

gastaldi avatar May 13 '22 21:05 gastaldi