Version: Spring IDE 4.5.0.RELEASE
I'm using Spring Boot 2.2.2 I have the following @ConfigurationProperties setup with @ConstructorBinding which works great during runtime but the IDE fails to auto complete. Any ideas?
package test;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConfigurationProperties(prefix = "someConfig")
public class ConfigProperties {
@ConstructorBinding
public ConfigProperties(NestedConfigProperties nested, NestedConfigProperties nested2) {}
}
package test;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConfigurationProperties
public class NestedConfigProperties {
@ConstructorBinding
public NestedConfigProperties(String dude) {}
public String getBob() {
return null;
}
public void setBob(String dude) {}
}
md5-11b259b0ff66e341274b65593557085f
{
"groups": [
{
"name": "",
"type": "test.NestedConfigProperties",
"sourceType": "test.NestedConfigProperties"
},
{
"name": "someConfig",
"type": "test.ConfigProperties",
"sourceType": "test.ConfigProperties"
}
],
"properties": [
{
"name": "dude",
"type": "java.lang.String",
"sourceType": "test.NestedConfigProperties"
},
{
"name": "someConfig.nested",
"type": "test.NestedConfigProperties",
"sourceType": "test.ConfigProperties"
},
{
"name": "someConfig.nested2",
"type": "test.NestedConfigProperties",
"sourceType": "test.ConfigProperties"
}
],
"hints": []
}
There are some situations in which STS doesn't rely on the metadata (which is not allways generated in Eclipse builds because the spring-boot configuration processor is a fincky beast that doesn't play allways nice with the incremental compiler).
I think this must be one of them. On top of that the @ConstructorBinding is relatively new and not as commonly used, so our implementation that tries to determine the properties by directly looking at the Java code is probably not handling this correctly.
This is just an initial guess on what may be going on, I will have to try to reproduce and debug it.
That makes sense I've noticed the problem doesn't seem to exist if using a dependency jar instead of another project in eclipse. Hopefully my test case will help you duplicate it for the non metadata case.
I have been able to reproduce this. Howeverm in Boot version 2.2.5 the given examples don't really work anymore because it doesn't like property names and prefix name in camelCase.
So running my sample app I get this error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Configuration property name 'someConfig' is not valid:
Invalid characters: 'C'
Bean: demoApplication
Reason: Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter
Action:
Modify 'someConfig' so that it conforms to the canonical names requirements.
I modified the example somewhat to make it 'work' again (I don't think we will strive to account for different behaviors across boot versions as it is already complex enough without dealing with such idiosyncracies). So the goal is somewhat more modest: to have things working properly and correctly with latest / current boot version.
To make the example work I needed to change the
@ConfigurationProperties(prefix = "someConfig")
into...
@ConfigurationProperties(prefix = "some-config")
After this, things work a little better (but still not 100% correctly).
My yaml file has this:
someConfig:
nested:
dude: dude
bob: bob
And STS now knows about both 'dude' and 'bob' as nested properties (they show up in completions and do not show a warning in the editor). This is still not 100% correct because I think only one of these two is 'really there' so the other should be a warning and should not be sugested as completion.
The camelCase in the annotation is not allowed anymore by spring boot. And I think that is a good thing. As it generates 'funky' metadata that further confuses the issue. I.e. the generated metadata has things like this:
{
"name": "someConfig.nested",
"type": "test.NestedConfigProperties",
"sourceType": "test.ConfigProperties"
}
Whereas the assumption that STS is making is that metadata is always giving properties in their hyphenated form (this is how the metadata is supposed to look and it would really complicate matters if we had to account for all the other 'relaxed name' formats to be used directly in the metadata.
Anyhow... long story short. I think we have two issues here:
the metadata should not contain camelCase names. This is, in a sense, invalid metadata. We don't consider the fact that STS is confused by this as a 'bug'. This issue should be adressed by using the hyphenated form in the @ConfigurationProperties.
When STS derives property names directly from a Java source type, it doesn't account for @ConstuctorBinding and gets confused by this. The result is property names like 'bob' in the example are being considered valid when they shouldn't be. We do consider that as bug that should be fixed.
@snicoll I would like to confirm with you whether you agree with this statement:
"the metadata should not contain camelCase names. This is, in a sense, invalid metadata. ..."
In other words it should be fine for the IDE to assume metadata is in hyphenated form only. I beleave that we are on the same page on this. I just want to confirm that is indeed the case.
That makes sense I've noticed the problem doesn't seem to exist if using a jar instead of another project in eclipse.
Good to know, yes it points in the direction that I thought. So its nice confirmation.
Hopefully my test case will help you duplicate it for the non metadata case
It does indeed. Thanks for providing detailed examples, that really helps a lot.
All that sounds good and accurate @kdvolder . Thanks for digging into this more.
"the metadata should not contain camelCase names. This is, in a sense, invalid metadata. ..."
Yes. The name of a property in the metadata file must have the canonical format, as documented in the reference guide.
This didn't make it yet into the next release. But the fix is in a branch waiting to be merged right after.
Martin suggested we can still merge it in last minute if it is 'low risk'. So... Okay, I think its low-impact and low-risk. The extra code just handles an extra case (when it sees specific annotation on a type). So its merged now.