hibernate/hibernate-orm · error · PropertyNotFoundException
Could not locate setter method for property '%s' of class '%
Error message
Could not locate setter method for property '%s' of class '%s'
What it means
Property access needs a writer as well as a reader. ReflectHelper.findSetterMethod searches the class hierarchy and interfaces for a public setFoo(...) whose single parameter equals the property type; when no method matches both the name and the parameter type, it throws PropertyNotFoundException. A setter taking a different type than the property is rejected exactly like a missing one.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java:736
Method potentialSetter = null;
for ( Method method : theClass.getDeclaredMethods() ) {
final String methodName = method.getName();
if ( method.getParameterCount() == 1 && methodName.equals( setterName ) ) {
potentialSetter = method;
if ( propertyType == null || method.getParameterTypes()[0].equals( propertyType ) ) {
break;
}
}
}
return potentialSetter;
}
public static Method findSetterMethod(final Class<?> containerClass, final String propertyName, final Class<?> propertyType) {
final Method setter = setterMethodOrNull( containerClass, propertyName, propertyType );
if ( setter == null ) {
throw new PropertyNotFoundException(
String.format(
Locale.ROOT,
"Could not locate setter method for property '%s' of class '%s'",
propertyName,
containerClass.getName()
)
);
}
return setter;
}
private static Method setterOrNull(Class<?>[] interfaces, String propertyName, Class<?> propertyType, String likelyMethodName) {
Method setter = null;
for ( int i = 0; setter == null && i < interfaces.length; ++i ) {
final var anInterface = interfaces[i];
if ( !shouldSkipInterfaceCheck( anInterface ) ) {
setter = setterOrNull( anInterface, propertyName, propertyType, likelyMethodName );
if ( setter == null ) {View on GitHub (pinned to fad1729dce)
Solutions
- Add a public setter setFoo(T) whose parameter type exactly matches the property/field type.
- Annotate the class or property with @Access(AccessType.FIELD) so Hibernate writes the field directly.
- For immutable values, map them as records/@Embeddable populated through the constructor instead of setters.
- If a setter already exists, make it public and align its parameter type with the mapped property type.
Example fix
// before: default property access, no setter
@Entity
public class Account {
@Id private Long id;
private BigDecimal balance; // no setBalance -> PropertyNotFoundException
}
// after: field access, no setter required
@Entity
@Access(AccessType.FIELD)
public class Account {
@Id private Long id;
private BigDecimal balance;
} Defensive patterns
Strategy: validation
Validate before calling
static void verifySetters(Class<?> entityClass, List<String> mappedPropertyNames) {
try {
java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(entityClass);
java.util.Set<String> writable = new java.util.HashSet<>();
for (java.beans.PropertyDescriptor pd : info.getPropertyDescriptors()) {
if (pd.getWriteMethod() != null) writable.add(pd.getName());
}
for (String name : mappedPropertyNames) {
if (!writable.contains(name)) {
throw new IllegalStateException("No setter for mapped property '" + name + "' on " + entityClass.getName());
}
}
} catch (java.beans.IntrospectionException e) {
throw new IllegalStateException("Cannot introspect " + entityClass.getName(), e);
}
} Type guard
static boolean hasSetter(Class<?> clazz, String property) {
try {
return new java.beans.PropertyDescriptor(property, clazz).getWriteMethod() != null;
} catch (java.beans.IntrospectionException e) {
return false;
}
} Try / catch
try {
SessionFactory sf = metadata.buildSessionFactory();
} catch (org.hibernate.PropertyNotFoundException e) {
// message names the property and class; add the setter or switch to @Access(AccessType.FIELD)
} Prevention
- Use @Access(AccessType.FIELD) on entity classes to decouple mapping from accessor presence.
- Keep setter parameter types identical to the corresponding field types.
- Build the SessionFactory in CI to catch accessor gaps early.
When it happens
Trigger: SessionFactory bootstrap or runtime property writes on a property-access mapping where the mapped property has no public setter, or where the only setter's parameter type differs from the property/field type. Direct calls to ReflectHelper.findSetterMethod with such a class/property pair hit the same path.
Common situations: Immutable or builder-style classes without setters; setter parameter type widened or narrowed during a refactor; package-private setters; @Embeddable components lacking setters; switching a class from field access to default property access without adding writers.
Related errors
- Could not locate getter method for property '%s' of class '%
- Class<?> '%s' declares both 'get' [%s] and 'is' [%s] variant
- Could not locate field for property named [" + containerJava
- Could not locate getter for property named [" + containerJav
- Could not locate field for property named [" + containerJava
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c4d61754b91c3d2c.
Report an issue: GitHub.