create yml with keysValues - java

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;

Related

Solr Spring boot application failed to run, giving bean error

Getting an error while running , a solr spring boot application, it says
"Parameter 0 of constructor in Controller required a bean of type Repository that could not be found."
"Consider defining a bean of type Repository in your configuration."
Here is my enitiy
#SolrDocument(collection = "content_core")
public class ContentDoc {
#Id
#Indexed
private String id;
#Indexed(name = "display_title", type = "string")
private String displayTitle;
}
Here is my solr config file
#EnableSolrRepositories(basePackages = "com.baeldung.repository.ContentDocRepository.spring.data.solr.repository", namedQueriesLocation = "classpath:solr-named-queries.properties")
#ComponentScan
public class SolrConfig {
#Bean
public SolrClient solrClient() {
return new HttpSolrClient.Builder("http://localhost:8983/solr").build();
}
#Bean
public SolrTemplate solrTemplate(SolrClient client) throws Exception {
return new SolrTemplate(client);
}
}
Here is my controller
#RequestMapping("/api/v1/content")
#AllArgsConstructor
#Slf4j
public class ContentDocController {
private final ContentDocRepository contentDocRepository;
#GetMapping("/searchfaq")
public Map<String, Object> searchFaq(#RequestParam("sectionId") Long sectionId,
#RequestParam("seachTerm") String searchTerm) {
// ContentDoc contentDoc = new ContentDoc();
// contentDoc.setContentId((long)1);
// contentDoc.setDisplayTitle("virat");
// contentDocRepository.save(contentDoc);
return null;
}
}
Here is my repository
#Qualifier("contentDocRepository")
public interface ContentDocRepository extends SolrCrudRepository<ContentDoc, String> {
public List<ContentDoc> findByName(String displayTitle);
}
this is the error that I am getting ->
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-10-20 18:22:47.836 ERROR 2760 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :
*********
APPLICATION FAILED TO START
*********
Description:
Parameter 0 of constructor in com.aa.aa.controller.ContentController required a bean of type 'com.aa.aa.repository.ContentDocRepository' that could not be found.
Action:
Consider defining a bean of type 'com.aa.aa.repository.ContentDocRepository' in your configuration.
I am trying to create an an api which searches data from DB , and using solr to index the db data.
I am following this page -> https://www.baeldung.com/spring-data-solr

The elements were left unbound Converting field into a map

I am trying to serialize the tenants field into a map so I can access it by key
Example:
multiTenancyProperties.getTenants().get("009-sss");
application.yml
multi-tenancy:
tenants:
007:
property: "Dummy property 1"
db: "db2"
008/dom:
property: "Dummy"
db: "sql"
009-sss:
property: "Dummy"
db: "sql"
Model:
#Configuration
#ConfigurationProperties(prefix = "multi-tenancy")
public class MultiTenancyProperties {
private Map<String, TenantDetails> tenants;
public Map<String, TenantDetails> getTenants() {
return tenants;
}
}
public class TenantDetails {
private String property = "";
private String db = "";
// etc
..
Inject into a class to use:
#Autowired
private MultiTenancyProperties multiTenancyProperties;
Error:
Binding to target [Bindable#9249f818 type = java.util.List<com.multitenancy.configuration.MultiTenancyProperties$TenantInstance>, value = 'provided', annotations = array<Annotation>[[empty]]] failed:
Property: multi-tenancy.tenants[7].db
Value: db2
Origin: URL [file:config/application.yml] - 14:11
Reason: The elements [multi-tenancy.tenants[7].db,multi-tenancy.tenants[7].property] were left unbound.
Property: multi-tenancy.tenants[7].property
Value: Dummy property 1
Origin: URL [file:config/application.yml] - 13:17
Reason: The elements [multi-tenancy.tenants[7].db,multi-tenancy.tenants[7].property] were left unbound.
Action:
Update your application's configuration
SpringBoot v2.6.2

SpringBoot 2 the elements were left unbound

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;
}

Map JSON POSTed in Java Spring Rest Controller to POJO

I am sending the following JSON object to my Java Spring application
{
"ewsUrl":"https://dummy.url.com",
"ewsIdentityToken":"12345",
"itemIds":["itemids"],
"entityId":null,
"documentType":"Dummy",
"documentStatus":"Record",
"filename":"message.eml",
"metadata":{"title":"message"}
}
I have defined an object public class RequestObject and in my controller I have
public RequestObject
testMyStuff(#CurrentUser User currentUser,
#RequestBody RequestObject myDummyObject) throws Exception {
return myDummyObject
}
My application returns the error Could not read document: Root name 'ewsUrl' does not match expected ('RequestObject') for type...etc
However if I send the JSON formatted like this it successfully maps the object:
{ "RequestObject":
{
"ewsUrl":"https://dummy.url.com",
"ewsIdentityToken":"12345",
"itemIds":["itemids"],
"entityId":null,
"documentType":"Dummy",
"documentStatus":"Record",
"filename":"message.eml",
"metadata":{"title":"message"}
}
}
I do not want to name the object in my JSON, I want to send as described in the first example. How do I achieve this?
UPDATE:
RequestObject.java
public class RequestObject {
public String ewsUrl;
public String ewsIdentityToken;
public String[] itemIds;
public String entityId;
public String documentType;
public String documentStatus;
public String filename;
public Metadata metadata;
public RequestObject() {
}
public static class Metadata {
public String title;
}
}
UPDATE2:
The way it is described in this example suggests that the object does not need to be named in the JSON data in the POST request. I think I am emulating this example, but I'm getting different results.
Is there a configuration for Jackson/Spring that I am missing?
Update 3:
The complete error message is:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException:
Could not read document:
Root name 'ewsUrl' does not match expected ('RequestObject') for type
[simple type, class uk.co.test.RequestObject] at [Source:
java.io.PushbackInputStream#7e223182; line: 2, column: 9];
nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Root name 'ewsUrl' does not match expected ('RequestObject') for type
[simple type, class uk.co.test.RequestObject]
There's some configuration settings that look like they can be defined for the ObjectMapper that controls the behaviour of the root element:
https://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/DeserializationFeature.html#UNWRAP_ROOT_VALUE - see SerializationFeature.html#WRAP_ROOT_VALUE as well.
UNWRAP_ROOT_MODULE is disabled by default according to the docs so not sure why you're seeing the behaviour you are.
Config example for spring is available at
http://docs.spring.io/spring-framework/docs/3.2.3.RELEASE/javadoc-api/org/springframework/http/converter/json/JacksonObjectMapperFactoryBean.html
Just use JSONArray instead of JSONObject
Update
You can get your Json Object via JSONArray.getJSONObject()

#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