hibernate/hibernate-orm · error · PropertyNotFoundException

Could not locate getter method for property '%s' of class '%

Error message

Could not locate getter method for property '%s' of class '%s'

What it means

Hibernate resolves mapped properties through JavaBean reflection. ReflectHelper.findGetterMethod walks the class, its superclasses, and all implemented interfaces looking for a public getFoo()/isFoo() accessor whose name matches the mapped property name. When no such method exists anywhere in the hierarchy, it throws PropertyNotFoundException at mapping time, meaning the mapping metadata names a property the Java class does not expose.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java:467

		}

		// check containerClass, and then its super types (if any)
		while ( getter == null && checkClass != null ) {
			if ( checkClass.equals( Object.class ) ) {
				break;
			}
			else {
				getter = getGetterOrNull( checkClass, propertyName );
				// if no getter found yet, check all implemented interfaces
				if ( getter == null ) {
					getter = getGetterOrNull( checkClass.getInterfaces(), propertyName );
				}
				checkClass = checkClass.getSuperclass();
			}
		}

		if ( getter == null ) {
			throw new PropertyNotFoundException(
					String.format(
							Locale.ROOT,
							"Could not locate getter method for property '%s' of class '%s'",
							propertyName,
							containerClass.getName()
					)
			);
		}

		ensureAccessibility( getter );

		return getter;
	}

	private static Method getGetterOrNull(Class<?>[] interfaces, String propertyName) {
		Method getter = null;
		for ( int i = 0; getter == null && i < interfaces.length; ++i ) {
			final var anInterface = interfaces[i];

View on GitHub (pinned to fad1729dce)

Solutions

  1. Fix the property name in the mapping so it exactly matches an existing getX()/isX() method (case-sensitive, first letter uppercase).
  2. Add the missing public getter to the entity or component class (or one of its superclasses).
  3. Switch the class or property to field access with @Access(AccessType.FIELD) so no getter is required.
  4. If the accessor exists but is non-public or non-standard, make it public or expose a conventional JavaBean getter.

Example fix

// before: mapping expects a getter that does not exist
@Entity
@Access(AccessType.PROPERTY)
public class User {
    private String emailAddress;
    @Column(name = "email")
    public String getEmail() { return emailAddress; } // mapping says "emial" -> PropertyNotFoundException
}

// after: mapping name matches the getter
@Column(name = "email")
public String getEmail() { return emailAddress; } // mapped as <property name="email"/>
Defensive patterns

Strategy: validation

Validate before calling

static void verifyGetters(Class<?> entityClass, List<String> mappedPropertyNames) {
    java.beans.BeanInfo info;
    try {
        info = java.beans.Introspector.getBeanInfo(entityClass);
    } catch (java.beans.IntrospectionException e) {
        throw new IllegalStateException("Cannot introspect " + entityClass.getName(), e);
    }
    java.util.Set<String> readable = new java.util.HashSet<>();
    for (java.beans.PropertyDescriptor pd : info.getPropertyDescriptors()) {
        if (pd.getReadMethod() != null) readable.add(pd.getName());
    }
    for (String name : mappedPropertyNames) {
        if (!readable.contains(name)) {
            throw new IllegalStateException("No getter for mapped property '" + name + "' on " + entityClass.getName());
        }
    }
}

Type guard

static boolean hasGetter(Class<?> clazz, String property) {
    try {
        return new java.beans.PropertyDescriptor(property, clazz).getReadMethod() != 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; align the mapping name with a real getter or add the accessor
}

Prevention

When it happens

Trigger: Building a SessionFactory where an hbm.xml <property name="..."> or a property-access (@Access(AccessType.PROPERTY)) attribute references a name that has no matching public getter on the class, superclasses, or interfaces. Also produced by direct calls to ReflectHelper.getGetter/findGetterMethod with a property name that has no accessor.

Common situations: Typo in the mapped property name versus the actual getter; renaming or removing getters during a refactor while mappings stay stale; non-public or unconventionally named accessors; property access on @Embeddable components without getters; mappings generated from one version of a class while a different version is deployed.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/4efff4ef25bff72a. Report an issue: GitHub.