Skip to content

Missing metadata when using @Name with a constructor-bound property #46599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

prishedko
Copy link
Contributor

Hello,

I'd like to suggest a fix for a bug that I've found while using @Name annotation with Type-safe Configuration Properties.

Problem description

When @Name annotation is used, the metadata items extracted from executable elements (like description and deprecation data) are missing. The following example demonstrates it:

Let's say we have record like this:

/**
 * @param namedPropertyExample this should be in the metadata description.
 */
@ConfigurationProperties(prefix = "example.properties")
public record ExampleProperties(
        @Deprecated
        @DeprecatedConfigurationProperty(reason = "Some reason")
        String namedPropertyExample) {}

Then it's generated metadata is:

{
  "groups": [
    {
      "name": "example.properties",
      "type": "org.some.example.ExampleProperties",
      "sourceType": "org.some.example.ExampleProperties"
    }
  ],
  "properties": [
    {
      "name": "example.properties.named-property-example",
      "type": "java.lang.String",
      "description": "this should be in the metadata description.",
      "sourceType": "org.some.example.ExampleProperties",
      "deprecated": true,
      "deprecation": {
        "reason": "Some reason"
      }
    }
  ],
  "hints": [],
  "ignored": {
    "properties": []
  }
}

But if @Name annotation is added:

/**
 * @param namedPropertyExample this should be in the metadata description.
 */
@ConfigurationProperties(prefix = "example.properties")
public record ExampleProperties(
        @Name("named.property")
        @Deprecated
        @DeprecatedConfigurationProperty(reason = "Some reason")
        String namedPropertyExample) {}

the metadata misses several attributes:

{
  "groups": [
    {
      "name": "example.properties",
      "type": "org.some.example.ExampleProperties",
      "sourceType": "org.some.example.ExampleProperties"
    }
  ],
  "properties": [
    {
      "name": "example.properties.named.property",
      "type": "java.lang.String",
      "sourceType": "org.some.example.ExampleProperties"
    }
  ],
  "hints": [],
  "ignored": {
    "properties": []
  }
}

Root cause and the fix descriptions

The root cause is the using Name#value for locating executable elements in org.springframework.boot.configurationprocessor.PropertyDescriptorResolver#extracted:

		String name = getPropertyName(parameter);
		TypeMirror type = parameter.asType();
		ExecutableElement getter = members.getPublicGetter(name, type);
		ExecutableElement setter = members.getPublicSetter(name, type);
		VariableElement field = members.getFields().get(name);
		RecordComponentElement recordComponent = members.getRecordComponents().get(name);

...

	private String getPropertyName(VariableElement parameter) {
		return getPropertyName(parameter, parameter.getSimpleName().toString());
	}

	private String getPropertyName(VariableElement parameter, String fallback) {
		AnnotationMirror nameAnnotation = this.environment.getNameAnnotation(parameter);
		if (nameAnnotation != null) {
			return this.environment.getAnnotationElementStringValue(nameAnnotation, "value");
		}
		return fallback;
	}

For the example above it means searching record component with name named.property. I'd like to suggest using parameter name for locating the executable elements:

		String parameterName = parameter.getSimpleName().toString();
		TypeMirror type = parameter.asType();
		ExecutableElement getter = members.getPublicGetter(parameterName, type);
		ExecutableElement setter = members.getPublicSetter(parameterName, type);
		VariableElement field = members.getFields().get(parameterName);
		RecordComponentElement recordComponent = members.getRecordComponents().get(parameterName);

When @name annotation is used on a property, metadata like javadoc and deprecation are not extracted. The root cause is that @Name.value is used for locating corresponding code element, and it can find something only @Name.value is the same as the code element name. This commit fixes the root cause.

Signed-off-by: Bohdan Pryshedko <[email protected]>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 30, 2025
@wilkinsona wilkinsona changed the title Using @Name annotation leads to a missed items in metadata. Missing metadata when using @Name with a constructor-bound property Jul 31, 2025
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 31, 2025
@wilkinsona wilkinsona added this to the 3.4.x milestone Jul 31, 2025
@snicoll snicoll self-assigned this Aug 4, 2025
@snicoll snicoll modified the milestones: 3.4.x, 3.4.9 Aug 4, 2025
snicoll pushed a commit that referenced this pull request Aug 4, 2025
Previously, when a property was customized with @name, getter, setter,
field, and record component were looked up using the custom name, rather
than the property name. This lead to missing information as the custom
name is not meant to match the field name, for instance.

This commit keeps the custom name, but uses the property name as for
other cases.

See gh-46599

Signed-off-by: Bohdan Pryshedko <[email protected]>
@snicoll snicoll closed this in 14820b0 Aug 4, 2025
@snicoll
Copy link
Member

snicoll commented Aug 4, 2025

Thanks for the detail explanation and the fix. Reviewing the code change, I've noticed another related problem, see #46662

snicoll added a commit that referenced this pull request Aug 4, 2025
This is a follow-up of gh-46599 where detecting the default value
suffer from the same problem. Rather than using a name, the resolver now
provides the field itself. This also adds a dedicated test for the use
of @name with Lombok.

Closes gh-46662
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants