Description
To generate the SchemaReport, the SchemaMappingGenerator uses BeanUtils#getPropertyDescriptor, which internally only caches those fields with public getters in the propertyDescriptors collection
@Nullable
PropertyDescriptor getPropertyDescriptor(String name) {
PropertyDescriptor pd = (PropertyDescriptor)this.propertyDescriptors.get(name);
if (pd == null && StringUtils.hasLength(name)) {
pd = (PropertyDescriptor)this.propertyDescriptors.get(StringUtils.uncapitalize(name));
if (pd == null) {
pd = (PropertyDescriptor)this.propertyDescriptors.get(StringUtils.capitalize(name));
}
}
return pd;
}
This does not match the PropertyFetchingImpl, which is the default responsible for resolving the field and fetching the data from it
private Object getPropertyViaFieldAccess(CacheKey cacheKey, Object object, String propertyName) throws FastNoSuchMethodException {
Class<?> aClass = object.getClass();
try {
Field field = aClass.getField(propertyName);
FIELD_CACHE.putIfAbsent(cacheKey, field);
return field.get(object);
} catch (NoSuchFieldException e) {
if (!USE_SET_ACCESSIBLE.get()) {
throw new FastNoSuchMethodException(cacheKey.toString());
}
// if not public fields then try via setAccessible
try {
Field field = aClass.getDeclaredField(propertyName);
field.setAccessible(true);
FIELD_CACHE.putIfAbsent(cacheKey, field);
return field.get(object);
} catch (SecurityException | NoSuchFieldException ignored2) {
throw new FastNoSuchMethodException(cacheKey.toString());
} catch (IllegalAccessException e1) {
throw new GraphQLException(e);
}
} catch (IllegalAccessException e) {
throw new GraphQLException(e);
}
}
How does this affect us?
We have a number of fields that are public final fields, but do not have public getters. Spring for GraphQL resolves the data, but the schema report warns that the fields are unmapped, which is untrue. We hook into the schema report and throw an exception if there are any unmapped fields by using GraphQlSourceBuilderCustomizer#inspectSchemaMappings. It is important for us to ensure that changes to our data model do not silently break our GraphQL API without us realising.