1717package org .springframework .graphql .execution ;
1818
1919import java .beans .PropertyDescriptor ;
20+ import java .lang .reflect .Method ;
21+ import java .lang .reflect .Modifier ;
2022import java .util .ArrayList ;
2123import java .util .Collections ;
2224import java .util .HashSet ;
5860import org .springframework .util .CollectionUtils ;
5961import org .springframework .util .LinkedMultiValueMap ;
6062import org .springframework .util .MultiValueMap ;
63+ import org .springframework .util .StringUtils ;
6164
6265/**
6366 * Inspect schema mappings on startup to ensure the following:
@@ -81,6 +84,15 @@ public final class SchemaMappingInspector {
8184
8285 private static final Log logger = LogFactory .getLog (SchemaMappingInspector .class );
8386
87+ /**
88+ * GraphQL Java detects "record-like" methods that match field names.
89+ * This predicate aims to match the method {@code isRecordLike(Method)} in
90+ * {@link graphql.schema.fetching.LambdaFetchingSupport}.
91+ */
92+ private static final Predicate <Method > recordLikePredicate = (method ) ->
93+ (!method .getDeclaringClass ().equals (Object .class ) && !method .getReturnType ().equals (Void .class ) &&
94+ method .getParameterCount () == 0 && Modifier .isPublic (method .getModifiers ()));
95+
8496
8597 private final GraphQLSchema schema ;
8698
@@ -173,6 +185,12 @@ private void checkFieldsContainer(
173185 checkField (fieldContainer , field , ResolvableType .forMethodReturnType (descriptor .getReadMethod ()));
174186 continue ;
175187 }
188+ // Kotlin function?
189+ Method method = getRecordLikeMethod (resolvableType , fieldName );
190+ if (method != null ) {
191+ checkField (fieldContainer , field , ResolvableType .forMethodReturnType (method ));
192+ continue ;
193+ }
176194 }
177195
178196 this .reportBuilder .unmappedField (FieldCoordinates .coordinates (typeName , fieldName ));
@@ -249,6 +267,19 @@ private PropertyDescriptor getProperty(ResolvableType resolvableType, String fie
249267 }
250268 }
251269
270+ @ Nullable
271+ private static Method getRecordLikeMethod (ResolvableType resolvableType , String fieldName ) {
272+ Class <?> clazz = resolvableType .resolve ();
273+ if (clazz != null ) {
274+ for (Method method : clazz .getDeclaredMethods ()) {
275+ if (recordLikePredicate .test (method ) && fieldName .equals (StringUtils .uncapitalize (method .getName ()))) {
276+ return method ;
277+ }
278+ }
279+ }
280+ return null ;
281+ }
282+
252283 private static boolean isNotScalarOrEnumType (GraphQLType type ) {
253284 return !(type instanceof GraphQLScalarType || type instanceof GraphQLEnumType );
254285 }
0 commit comments