Here is an example of my problem. when no value is supplied to default-name in yml file. #DefaultValue should step in and fill with "Name". However, is not how it behaves. An empty string is assigned to defaultName
application.yml:
account:
default-name:
class:
#ConstructorBinding
#ConfigurationProperties(prefix = "account")
public class Account {
private final String defaultName;
public Account(#DefaultValue("Name") String defaultName) {
this.defaultName = defaultName;
}
..
..
}
Related
I have the following configuration in my Spring boot's application.yml file:
project:
country-properties:
france:
capital: paris
population: 60
And I have the the properties class : CountryProperties :
#Getter
#AllArgsConstructor
#ConstructorBinding
#ConfigurationProperties(prefix="project.country-properties")
public class CountryProperties {
private Map<String, CountryData> countryProperties;
#Getter
#Setter
public static class CountryData {
private String capital;
private Integer population;
}
However my CountryProperties is always null, and it's because of a failed mapping with the CountryData object.
Any ideas what is wrong with what I wrote?
You have the annotation #ConstructorBinding. This annotation tells Spring to look for a constructor in your class that has parameters corresponding to your configuration properties, and then will bind the properties.
What you are missing is:
public CountryProperties(Map<String, CountryData> countryProperties) {
this.countryProperties = countryProperties;
}
Update:
After inspecting your code again, it looks like you aren't mapping the configuration correctly to the instance field. Please update your #ConfigurationProperties(prefix="project.country-properties") to #ConfigurationProperties(prefix="project").
Also replace the #ConstructorBinding with #Configuration.
Assume that there is a yaml configuration:
foo:
a:
b:
c:
d:
Generally, you will create an object like this:
#Data
#Validated
#Component
#ConfigurationProperties(prefix = "foo")
public class FooProperties {
#NotBlank
private String a;
// b c and d
}
But for the consideration of the project structure, I need to divide them into multiple objects in different packages, And they will use the same prefix.
package one:
#Data
#Validated
#Component
#ConfigurationProperties(prefix = "foo")
public class AProperties {
// only a property
#NotBlank
private String a;
}
package two:
#Data
#Validated
#Component
#ConfigurationProperties(prefix = "foo")
public class BProperties {
// only b property
#NotBlank
private String b;
}
...
And now, when my project fetch config from config server, Spring will say:
***************************
APPLICATION FAILED TO START
***************************
Binding to target [Bindable#2b32cd10 type = AProperties, value = 'provided', annotations = array<Annotation>[#org.springframework.boot.context.properties.ConfigurationProperties(ignoreInvalidFields=false, ignoreUnknownFields=false, prefix=foo, value=foo), #org.springframework.validation.annotation.Validated(value={})]] failed:
Property: foo.b
Value: someValue
Origin: "foo.b" from property source "bootstrapProperties-xxx"
Reason: The elements [foo.b] were left unbound.
So, How can I bind the same prefix with multiple properties class? Thx~
Environment:
spring-boot v2.0.4 RELEASE
spring-data-aerospike v2.0.1.RELEASE
java - 8
Here are my application code and properties.
// application.properties
aerospike.hosts=xxx:3000
aerospike.namespace=test
// aerospike configuration class
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(AerospikeConfiguration.AerospikeConfigurationProperties.class)
#EnableAerospikeRepositories(basePackageClassses = TestAeroRepository.class)
public class AerospikeConfiguration extends AbstractAerospikeDataConfiguration {
private final AerospikeConfigurationProperties aerospikeConfigurationProperties;
#Override
protected Collection<Host> getHosts() {
return Host.parseServiceHosts(aerospikeConfigurationProperties.getHosts());
}
#Override
protected String nameSpace() {
return aerospikeConfigurationProperties.getNamespace();
}
#Data
#Validate
#ConfigurationProperties("aerospike")
public static class AerospikeConfigurationProperties {
#NotEmpty
String hsots;
#NotEmpty
String namespace;
}
}
# Entity class
#Value
#Document
#Builder(toBuilder = true)
#AllArgsConstructor
public class testEntity() {
#Id
int id;
#Field
String name;
#Field
String timestamp;
}
#Repository
public interface TestAeroRepository extends AerospikeRepository<TestEntity, Integer> {
}
public interface TestAeroService {
void save();
}
#Service
#RequiredArgsConstructor
public class TestAeroServiceImpl implements TestAeroService {
private final TestAeroRepository testAeroRepository;
#Override
public void save(TestEntity entity) {
testAeroRepository.save(entity);
}
}
I checked Aerospike client connection has no problem.
But error is occurred when save() method is executed.
org.springframework.cglib.core.ReflectUtils.defineClass(Ljava/lang/String;[BLjava/lang/ClassLoader;Ljava/security/ProtectionDomain;Ljava/lang/Class;)Ljava/lang/Class;
Have to make sets before execute the application? I didn't make sets.
Any problem with my code?
You’re using an old version of spring-data-aerospike (2.0.1.RELEASE was released on April 2019) is there any chance you can upgrade to the latest version? 2.4.2.RELEASE
You can see how to setup a simple spring data aerospike application here: https://medium.com/aerospike-developer-blog/simple-web-application-using-java-spring-boot-aerospike-database-and-docker-ad13795e0089
Please share the entire project’s code and the entire exception.
I would look into:
The configuration class (The Aerospike Beans creation).
The content of the testEntity class - are you using #Id annotation on the primary key field?
Extending the repository class with specifying the testEntity object (… extends AerospikeRepository<testEntity, Object> {) you can see an example in the link I added.
The set is automatically created and takes the name of your object class, which is testEntity in your case. For example, based on your code, if you do not specify a collection in the #Document annotation a set named "testEntity" will automatically be created. I added the #Document(collection = "testEntitys") annotation and all I did was create two set. Once you insert your first record, run the "SHOW SETS" aql command and it will be there. So that's one way to do it.
In a #ConfigurationProperties bean, I could map the customers property of the application.yml file below to List<Customer>, but I would like to instead map it to a Jackson JsonNode. Is this possible? If so, how?
shop:
name: "Sam's Bikes"
customers:
- name: Lucy
age: 26
- name: James
age: 24
This is what I'd like to achieve:
#ConfigurationProperties("shop")
public class ShopProperties() {
private String name;
private JsonNode customers;
}
Since customers in application.yml are in Array of objects format, i would recomend either to collect them into List<Customer> or List<Map<String,Object>> using below code, #Data is lombok annotation, if you are not using lombok add getters and setters
#ConfigurationProperties("shop")
#Data
#Configuration
public class TestConfig {
private String name;
private List<Map<String,Object>> customers; //[{name=Lucy, age=26}, {name=James, age=24}]
}
I have this entity:
#Data
#Document(indexName = "foo.user")
public class ElUser {
#Id
private String id;
#Field(type = FieldType.Text)
private String fullName;
}
And this Repository:
#Repository
interface ElasticsearchUserRepository extends ElasticsearchRepository<ElUser, String> {
List<ElUser> findAllByFullNameIsLike(String name);
}
And it works fine. But I want to use a prefix like this(.withPathPrefix("foo")):
#EnableElasticsearchRepositories
#Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
#Bean
#Override
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.withPathPrefix("foo")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
And remove it from entity:
#Document(indexName = "user")
But I get an exception:
org.springframework.data.elasticsearch.NoSuchIndexException: Index [foo] not found.; nested exception is [foo] ElasticsearchStatusException[Elasticsearch exception [type=index_not_found_exception, reason=no such index [foo]]]
The path prefix you can configure is not a prefix for the index name like foo in foo.user, it's for the path in the URL which might be needed for some routing/proxying/dispatching software between the application and Elasticsearch.
Let's imagine you have two Elasticsearch clusters at foo:9200 and bar:9200 and there is a nginx proxy in front of them at proxy:8080 which will route an request to proxy:8080/foo/abc to foo:9200/abc and proxy:8080/bar/abc to bar:9200/abc, then you would configure you client to connect to proxy:8080 with a pathPrefix of foo.
So it's not for the use case you have.
Edit:
I have an example of how to provide an index prefix in my blog post "How to provide a dynamic index name in Spring Data Elasticsearch using SpEL", in the section Use a value from the application configuration, that might fit your needs.
_