SpringBoot 2 the elements were left unbound - java

i have a file application.yml with my Spring Boot application which is not willing to run.
According to logs the reason of The elements [simulator.geo.b12,simulator.geo.b13,simulator.geo.b21,simulator.geo.c6,simulator.geo.host] were left unbound. This property however is set in application.yml and compiler is even returning it's value.
I'll really appreciate if someone could lend me a hand with that issue.
simulator:
geo:
host: http://localhost:8080/
b12: http://localhost:8080/geo/b12
b13: http://localhost:8080/geo/b13
b21: http://localhost:8080/geo/b21
c6: http://localhost:8080/geo/c6
and java class
#Getter
#Configuration
#ConfigurationProperties(prefix = "simulator",ignoreUnknownFields = false)
public class VendorSimulatorProperties {
#Value("${simulator.geo.host:http://localhost:8080/}")
private String initUrl;
#Value("${simulator.geo.b12}")
private String geoB12Url;
#Value("${simulator.geo.b13}")
private String geoB13Url;
#Value("${simulator.geo.b21}")
private String geoB21Url;
#Value("${simulator.geo.c6}")
private String geoC6Url;
}
when i start to run application, i got the error msg :
**************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target [Bindable#1c140c7c type = com.mathartsys.dlc.thirdparty.vendor.config.VendorSimulatorProperties$$EnhancerBySpringCGLIB$$eb0a550b, value = 'provided', annotations = array<Annotation>[#org.springframework.boot.context.properties.ConfigurationProperties(prefix=simulator, value=simulator, ignoreUnknownFields=false, ignoreInvalidFields=false)]] failed:
Property: simulator.geo.b12
Value: http://localhost:8080/geo/b12
Origin: class path resource [config/application-dev.yml]:204:14
Reason: The elements [simulator.geo.b12,simulator.geo.b13,simulator.geo.b21,simulator.geo.c6,simulator.geo.host] were left unbound.
Property: simulator.geo.b13
Value: http://localhost:8080/geo/b13
Origin: class path resource [config/application-dev.yml]:205:14
Reason: The elements [simulator.geo.b12,simulator.geo.b13,simulator.geo.b21,simulator.geo.c6,simulator.geo.host] were left unbound.
Property: simulator.geo.b21
Value: http://localhost:8080/geo/b21
Origin: class path resource [config/application-dev.yml]:206:14
Reason: The elements [simulator.geo.b12,simulator.geo.b13,simulator.geo.b21,simulator.geo.c6,simulator.geo.host] were left unbound.
Property: simulator.geo.c6
Value: http://localhost:8080/geo/c6
Origin: class path resource [config/application-dev.yml]:207:13
Reason: The elements [simulator.geo.b12,simulator.geo.b13,simulator.geo.b21,simulator.geo.c6,simulator.geo.host] were left unbound.
Property: simulator.geo.host
Value: http://localhost:8080/
Origin: class path resource [config/application-dev.yml]:203:15
Reason: The elements [simulator.geo.b12,simulator.geo.b13,simulator.geo.b21,simulator.geo.c6,simulator.geo.host] were left unbound.
this problem had confuse me long time, i hope someone can give me some advice;
i used springboot 2.0
thanks

The problem is that you are using the #ConfigurationProperties in a wrong way. You use either #ConfigurationProperties or #Value but not both.
The solution either fix your class to be usable for #ConfigurationProperties or remove the #ConfigurationProperties annotation.
#Getter
#Setter
#Component
#ConfigurationProperties(prefix = "simulator.geo",ignoreUnknownFields = false)
public class VendorSimulatorProperties {
private String host = "http://localhost:8080/";
private String b12;
private String b13;
private String b21;
private String c6;
}
You need to fix the prefix it should be simulator.geo and your properties should be named after the keys in your file. You will also require setter next to the getter. However this will also need to change the rest of your configuration, to use the newly generated getters.
For you it is probably easier to remove #ConfigurationProperties as you weren't really using them in the first place.

I got the same issue, but in my case, it's because I added #AllArgsConstructor but did not add #NoArgsConstructor. As the result, Spring was unable to create the config object (using the default constructor) so it just skips processing the configs and print out the warning.
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor // need to add this if you have #AllArgsConstructor
public class ServerConfiguration {
private String host;
private int port;
}

Related

SpringBoot 2.6.3 not binding #ConfigurationProperties on List of Objects

I know this must be simple, and I've seen multiple similar questions, however my entire setup seems to be ok (as solutioned in the other posts), yet this problem persists.
Here's my setup
Environment
Spring Boot 2.6.3
Java 17
application.yml
platforms:
configs:
- platform: ABC
base-url: https://some-url-01.com/api
description:
logo:
- platform: DEF
base-url: https://some-url-02.com/api
description:
logo:
Config Properties
#Data
#ConstructorBinding
#ConfigurationProperties(prefix = "platforms")
public class PlatformProperties {
private final List<PlatformConfig> configs = new ArrayList<>();
#Data
public static class PlatformConfig {
private final Platform platform;
private final String baseUrl;
private final String description;
private final String logo;
}
}
Platform.java - a simple enum
public enum Platform {
ABC, DEF
}
Configuration
#Slf4j
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(PlatformProperties.class)
public class ClientConfig {
private final PlatformProperties platformProperties;
#PostConstruct
public void showProperties(){
platformProperties.getConfigs().forEach(System.out::println);
}
}
This entire setup seems perfectly fine (Ref: Spring Docs), however platformProperties.getConfigs() is always empty because there was no binding on platforms.configs as defined from the application.yml
I have a similar setup on a different project (springboot 2.5.7 / Java 8) where everything works exactly as expected.
What about this setup/configs is wrong???
Yah, I solved this a long time ago, just wanted to provide the answer, and it was quite simple too.
You see this line?
private final List<PlatformConfig> configs = new ArrayList<>();
That was the culprit.
Notice that the configs variable is final and was already assigned a new ArrayList<>() as it's value, hence it was immutable.
Solution was to remove the initial assignment so the line became;
private final List<PlatformConfig> configs;
The constructor binding went OK and the configs values were populated as expected.

Springboot application dont get correctly the value from Spring Config Server properties [duplicate]

This question already has answers here:
#Value from application.yml returns wrong value
(2 answers)
Closed 1 year ago.
I have a little issue and i really dont know why this is happening
#RefreshScope
#Configuration
#Getter
public class ConfigProperties {
#Value("${receipts.Application}")
private String application;
#Value("${receipts.ApplicationIdMT}")
private String applicationIdMT;
#Value("${receipts.IdComercioMT}")
private String idComercioMT;
//more properties
}
i have this configuration class i get the values from a application.yml this file is in a git repository because my proyect use a config server to fetch the values
my application.yml in git repo looks like this:
receipts:
Application: NAVERU
ApplicationIdMT: b96f9c62-e6a
IdComercioMT: 02500000012
//more properties
when i fetch the values something weird happen, a example of my class is this:
//logic and imports....
public class ClientBase {
#Autowired
protected ConfigProperties configProperties;
public void printValues(){
String application= configProperties.getApplication();
String applicationIdMT= configProperties.getApplicationIdMT();
String idComercioMT= configProperties.getIdComercioMT();
System.out.println("aplication: "+application);
System.out.println("idMt: "+applicationIdMT);
System.out.println("idComerceMt: "+idComercioMT);
}
}
And when i see the values in console:
aplication: NAVERU
idMt: b96f9c62-e6a
idComerceMt: 352321546
i dont understeand why idComerceMt comes with that value because like i show the real value is 02500000012
The problem is that the value of IdComercioMT is being read as a number, and being 0-prefixed, it is being parsed in octal.
02500000012(octal) = 352321546(decimal)
Since the Configuration class wants the value as a String, you can fix it easily by quoting the value:
receipts:
Application: NAVERU
ApplicationIdMT: b96f9c62-e6a
IdComercioMT: '02500000012'
# more properties
Check the values in your property file in target\BOOT-INF\classes

create yml with keysValues

I have a .yml in my Springboot, I am trying create an array in my .yml with a class java (key/value), but I get error when I execute the app.
Yml:
profiles:
- type: user
url: www
- type: admin
url: http
Then I get datas in my implements using my class Profile:
#Value("${profiles}")
private List<Profile> profiles;
Finally my class:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class Profile {
private String type;
private String url;
}
Error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'api': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'profiles' in value "${profiles}"
I want read my yml for check values:
for (int i = 0; i < this.profiles.size(); i++) {
Profile pr = this.profiles.get(i);
System.out.println(pr.getType() + pr.getUrl());
}
Please I need help, I search in google but only get "Arrays" ['1','2','3'] o two Arrays ...
I need a structure the key/value
profiles: [
{
'key':'user',
'url': 'www'
},
{
'key':'admin',
'url': 'http'
}
]
Ahh !! My profiles can have 2,4, 1000 registros... that's why I pick it up List
#Value("${profiles}")
private List<Profile> profiles;

Reason: The elements were left unbound

How can I load List of objects from configuration yml file in java springboot application?
I already tried several sources:
configuration-properties-in-spring-boot
spring-boot-configurationproperties-example
SpringBoot 2 the elements were left unbound
Stack: Java 11, SpringBoot 2.1.4, Lombok, configuration file in .yml format.
I tried to implement simple #Component, which will load data from configuration file.
Configuration values are:
allowed:
- first-crossroad: ONE
second-crossroad: TWO
third-crossroad: TWO
fourth-crossroad: THREE
- first-crossroad: ONE
second-crossroad: THREE
third-crossroad: TWO
fourth-crossroad: ONE
Java class for data loading is:
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "")
#Data
public class AllowedCrossroads {
private List<CrossroadCombination> allowed;
}
Java CrossroadCombination object definition:
#Data
#Builder
#AllArgsConstructor
public class CrossroadCombination {
private String firstCrossroad;
private String secondCrossroad;
private String thirdCrossroad;
private String fourthCrossroad;
}
I expected values to be loaded during application run. But I am getting error:
Property: allowed[0].first-crossroad
Value: ONE
Origin: class path resource [application.yml]:644:17
Reason: The elements [allowed[0].first-crossroad,allowed[0].fourth-crossroad,allowed[0].second-crossroad,allowed[0].third-crossroad,allowed[1].first-crossroad,allowed[1].fourth-crossroad,allowed[1].second-crossroad,allowed[1].third-crossroad,allowed[2].first-crossroad,allowed[2].fourth-crossroad,allowed[2].second-crossroad,allowed[2].third-crossroad] were left unbound.
(One of many) Solution:
add: #NoArgsConstructor
to java class:
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class CrossroadCombination {
private String firstCrossroad;
private String secondCrossroad;
private String thirdCrossroad;
private String fourthCrossroad;
}
Explanation:
It is because when we create an object, we need to have an empty object and then fill it with data. This is why we need no args constructor.
Anyway solution from "#Daniel V" is also correct and thanks for that one!
Making The Inner class as static will work
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "")
#Data
public class AllowedCrossroads {
private List<CrossroadCombination> allowed;
#Data
public static class CrossroadCombination {
private String firstCrossroad;
private String secondCrossroad;
private String thirdCrossroad;
private String fourthCrossroad;
}
}
including Getters and Setters for all fields solved the issue
Did you try with java ResourceBundle library?
for example:
ResourceBundle configApp = ResourceBundle.getBundle("path to your configuration file");
after that you can use configApp like so:
configApp.getString("first-crossroad");
can you try that and tell me how it goes.
EDIT:
The data in your configuration file if your planning to use ResourceBundle should look like this:
allowed=[first-crossroad= ONE, second-crossroad= TWO, third-crossroad= TWO,fourth-crossroad= THREE,first-crossroad= ONE, second-crossroad= THREE,third-crossroad= TWO, fourth-crossroad= ONE]
the "[]" isn't neccesary but it makes it look more readable
then you call it like this:
configApp.getObject("allowed");
that will store it like this:
[first-crossroad= ONE, second-crossroad= TWO, third-crossroad= TWO,fourth-crossroad= THREE,first-crossroad= ONE, second-crossroad= THREE,third-crossroad= TWO, fourth-crossroad= ONE]
then you can cast this to an array or play with it like this.
In my case the variable name is not matched. Please check all fields names and mapping configuration key names.

#ConfigurationProperties prefix not working

.yml file
cassandra:
keyspaceApp:junit
solr:
keyspaceApp:xyz
Bean
#Component
#ConfigurationProperties(prefix="cassandra")
public class CassandraClientNew {
#Value("${keyspaceApp:#null}") private String keyspaceApp;
Main method file
#EnableAutoConfiguration
#ComponentScan
#PropertySource("application.yml")
public class CommonDataApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CommonDataApplication.class)
.web(false).headless(true).main(CommonDataApplication.class).run(args);
}
}
TestCase
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = CommonDataApplication.class)
#IntegrationTest
#EnableConfigurationProperties
public class CassandraClientTest {
#Autowired
CassandraClientNew cassandraClientNew;
#Test
public void test(){
cassandraClientNew.getSession();
System.out.println(" **** done ****");
}
}
Instead of setting junit as the keyspaceApp it sets xyz.
Looks like prefix="cassandra" not working
It looks like you are trying to use Spring Boot Typesafe Configuration Properties feature.
So in order to have it working correctly, you have to add a few changes to your code:
First of all, your CommonDataApplication class should have #EnableConfigurationProperties annotation e.g.
#EnableAutoConfiguration
#ComponentScan
#PropertySource("application.yml")
#EnableConfigurationProperties
public class CommonDataApplication {
public static void main(String[] args) {
// ...
}
}
I do not believe you need #PropertySource("application.yml") annotation as application.yml (as well as application.properties and application.xml) is a default configuration file used by Spring Boot.
Your CassandraClientNew class does not need to have #Value annotation prefixing keyspaceApp property. And your keyspaceApp has to have a setter method.
#Component
#ConfigurationProperties(prefix="cassandra")
public class CassandraClientNew {
private String keyspaceApp;
public void setKeyspaceApp(final String keyspaceApp) {
this.keyspaceApp = keyspaceApp;
}
}
BTW, if you are using List's or Sets and you initialise collections (e.g. List<String> values = new ArrayList<>();), then only getter is required. If a collection is not initialised then you need to provide a setter method too (otherwise an exception will be thrown).
I hope that will help.
General answer
1. In your properties file (application.properties or application.yml)
# In application.yaml
a:
b:
c: some_string
2. Declare your class:
#Component
#ConfigurationProperties(prefix = "a", ignoreUnknownFiels = false)
public class MyClassA {
public MyClassB theB; // This name actually does not mean anything
// It can be anything
public void setTheB(MyClassB theB) {
this.theB = theB;
}
public static MyClassB {
public String theC;
public void setTheC(String theC) {
this.theC = theC;
}
}
}
3. Declare public setters! And this is crucial!
Make sure to have these public methods declared in the above classes. Make sure they have "public" modifier.
// In MyClassA
public void setTheB(MyClassB theB) {
this.theB = theB;
}
// In MyClassB
public void setTheC(String theC) {
this.theC = theC;
}
That's it.
Final notes
The property names in your classes do not mean anything to Spring. It only uses public setters. I declared them public not to declare public getters here. Your properties may have any access modifiers.
Pay attention to the attribute "ignoreUnknownFields". Its default value is "true". When it is "false" it will throw exception if any of your properties in file "application.yml" was not bound to any class property. It will help you a lot during debugging.
I don't know where the "xyz" came from (maybe you aren't showing your whole application.yml?). You don't normally bind with #Value in #ConfigurationProperties though (it has no way of knowing what your prefix is). Did you actually #EnableCongigurationProperties anywhere? Are you using SpringApplication to create the application context?
Just add a public setter or #Setter from Lombok.
I had a similar but different issue compared to OP, and couldn't find an answer anywhere, so I'll post about it. Let say you're trying to use Lombok to go and auto generate the getters & setters & other fields for you in your configuration file.
Here is an example:
#Configuration
#ConfigurationProperties(prefix = "address")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class AddressConfig {
private Endpoint endpoint;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public static class Endpoint {
private String url;
}
}
If using lombok #Getter & #Setter annotations (or #Data which also takes care of #Getter & #Setter), then make sure to also have this annotation:
#Accessors(fluent = false)
The reason: spring needs the setter methods to actually populate the configuration for you. However, in the above example, here's how the url would be set internally in spring:
addressConfig.getEndpoint().setUrl("...");
You can see that getters are prefixed with get and setters are prefixed with set.
If you do NOT have #Accessors(fluent = false) set, then the setters will use the fluent style of accessors, which don’t prepend getters with the word get and setters with the word set. This breaks springs ability to populate configuration pojos properly.
Spring will not tell you this when you execute the application. You only get null pointer exceptions when trying when your application tries to use those configuration variables. I only realized I need to put an #Accessors(fluent = false) annotation after hours of trial & error since I couldn’t find the answer on google or stackoverflow.
side note: intellij will warn you that false is the default value for #Accessors. This is wrong -_-
Anyways, here's the configuration class with the annotation (yes, you only need to add this at the top of the class, just one time, and not in the inner classes).
#Configuration
#ConfigurationProperties(prefix = "address")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class AddressConfig {
private Endpoint endpoint;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Accessors(fluent = false)
#Builder
public static class Endpoint {
private String url;
}
}
That's my FULL solution for this case:
My Class will be receiving the properties:
// Setter are CRUCIAL for PropertySource + ConfigurationProperties works properly
#PropertySource(value = "classpath:application-dev.yml", ignoreResourceNotFound = true)
#ConfigurationProperties(prefix = "spring.data.mongodb")
#Setter
#Profile("dev")
#Configuration
#EnableReactiveMongoRepositories(
basePackages = {
"com.webflux.mongo2.project.repo",
"com.webflux.mongo2.task.repo"})
public class MyClassGettingTheProperties {
private String database;
private String host;
private String port;
private String username;
private String password;
private String authenticationDatabase;
}
My property file - application-dev.yml:
spring:
data:
mongodb:
database: ${MONGO_INITDB_DATABASE}
host: ${HOST}
port: ${PORT}
username: ${MONGO_INITDB_ROOT_USERNAME}
password: ${MONGO_INITDB_ROOT_PASSWORD}
authentication-database: ${AUTH_MAN}
My docker-compose which is the "origin" of the properties:
version: "3.4"
x-common-variables:
&env-vars
PORT_API: 1313
MONGO_INITDB_DATABASE: zzzzz
HOST: yyyyy
PORT: 27017
MONGO_INITDB_ROOT_USERNAME: xxxxx
MONGO_INITDB_ROOT_PASSWORD: xxxxxxx
AUTH_MAN: kkkkk
volumes:
api_vol:
networks:
mongo-cluster:
services:
api-db:
container_name: api-db
image: mongo:4.4.4
restart: always
ports:
- "27017:27017"
networks:
- mongo-cluster
volumes:
- api_vol:/data/db
environment:
*env-vars

Categories