Skip to content

Commit

Permalink
Support for inherited interfaces (#65) (#298)
Browse files Browse the repository at this point in the history
  • Loading branch information
richharms authored Dec 12, 2023
1 parent 4fc9ac8 commit 0d0aa22
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import graphql.annotations.processor.retrievers.GraphQLInterfaceRetriever;
import graphql.annotations.processor.retrievers.GraphQLObjectInfoRetriever;
import graphql.annotations.processor.searchAlgorithms.SearchAlgorithm;
import graphql.annotations.processor.util.ClassUtils;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLObjectType;
Expand Down Expand Up @@ -95,7 +96,7 @@ public GraphQLObjectType.Builder getOutputObjectBuilder(Class<?> object, Process
}
}

for (Class<?> iface : object.getInterfaces()) {
for (Class<?> iface : ClassUtils.getAllInterfaces(object)) {
if (iface.getAnnotation(GraphQLTypeResolver.class) != null) {
String ifaceName = graphQLObjectInfoRetriever.getTypeName(iface);
if (container.getProcessing().contains(ifaceName)) {
Expand Down
95 changes: 95 additions & 0 deletions src/main/java/graphql/annotations/processor/util/ClassUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Licensed 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
*/

package graphql.annotations.processor.util;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
* Operates on classes without using reflection.
*
* <p>
* This class handles invalid {@code null} inputs as best it can. Each method documents its behavior in more detail.
* </p>
*
* <p>
* The notion of a {@code canonical name} includes the human readable name for the type, for example {@code int[]}. The
* non-canonical method variants work with the JVM names, such as {@code [I}.
* </p>
*
* <p>
* This class and the functions contained within are from the Apache commons-lang project.
* </p>
*
*/
public class ClassUtils {

/**
* Gets a {@link List} of all interfaces implemented by the given class and its superclasses.
*
* <p>
* The order is determined by looking through each interface in turn as declared in the source file and following its
* hierarchy up. Then each superclass is considered in the same way. Later duplicates are ignored, so the order is
* maintained.
* </p>
*
* @param cls the class to look up, may be {@code null}
* @return the {@link List} of interfaces in order, {@code null} if null input
*/
public static List<Class<?>> getAllInterfaces(final Class<?> cls) {
if (cls == null) {
return null;
}

final LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<>();
getAllInterfaces(cls, interfacesFound);

return new ArrayList<>(interfacesFound);
}

/**
* Gets the interfaces for the specified class.
*
* @param cls the class to look up, may be {@code null}
* @param interfacesFound the {@link Set} of interfaces for the class
*/
private static void getAllInterfaces(Class<?> cls, final HashSet<Class<?>> interfacesFound) {
while (cls != null) {
final Class<?>[] interfaces = cls.getInterfaces();

for (final Class<?> i : interfaces) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
}
}

cls = cls.getSuperclass();
}
}

/**
* ClassUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
* {@code ClassUtils.getShortClassName(cls)}.
*
* <p>
* This constructor is public to permit tools that require a JavaBean instance to operate.
* </p>
*/
public ClassUtils() {
}

}
6 changes: 5 additions & 1 deletion src/test/java/graphql/annotations/GraphQLFragmentTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.TypeResolutionEnvironment;
import graphql.annotations.GraphQLFragmentTest.MyInterface;
import graphql.annotations.annotationTypes.GraphQLField;
import graphql.annotations.annotationTypes.GraphQLTypeResolver;
import graphql.annotations.processor.GraphQLAnnotations;
Expand Down Expand Up @@ -95,7 +96,10 @@ public MyObject2 getMy() {
}
}

public static class MyObject2 implements MyInterface {
public static class MyObject2 extends SuperClass {
}

public static class SuperClass implements MyInterface {
public String getA() {
return "a2";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void testUnion() {
public void testInterfaces() {
GraphQLObjectType object = this.graphQLAnnotations.object(TestObject.class);
List<GraphQLNamedOutputType> ifaces = object.getInterfaces();
assertEquals(ifaces.size(), 1);
assertEquals(ifaces.size(), 2);
assertEquals(ifaces.get(0).getName(), "TestIface");
}

Expand Down

0 comments on commit 0d0aa22

Please sign in to comment.