Spring Boot #ConfigurationProperties - spring-boot

so I'm kinda new to Springboot and I'm trying to get the value from application.properties. I want to get multiple value from the application.properties and insert it into a list. At first, I tried to get the value from controller class and it works. Now I tried to get the value from a new class, but the value won't show up and it's showing an error because it says that it's null. Am i missing an annotation or did i do something wrong in the code? Below is my code.
application.properties:
example.name[0] = asdf
example.name[1] = qwer
List Value class:
#ConfigurationProperties(prefix = "example")
#Configuration
public class NameProperties {
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
What i tried in controller and worked:
#RestController
#CrossOrigin
#RequestMapping("/tes/**")
public class NameController {
#Autowired
NameProperties property = new NameProperties();
#GetMapping
public String tes() {
String name = property.getName().get(0);
System.out.println(name);
return name;
}
}
In the new class that doesn't work:
#Component
public class NameConfiguration {
#Autowired
NameProperties property = new NameProperties();
public void getName(int index) {
System.out.println(property.getName().get(0));
}
}
The code to test the new class in the controller:
#RestController
#CrossOrigin
#RequestMapping("/tes/**")
public class NameController {
NameConfiguration conf = new NameConfiguration();
#GetMapping
public String tes() {
conf.getName(0);
}
}
Is it because the value doesn't get injected when I call the class or what should I do? Appreciate any kind of help. Thanks!

Hello friend when you declare your class as a Spring Bean you shouldn't initialize the object yourself other the properties define in it will not be injected by Spring, so you should let spring help you with that, try these class below
NameProperties
#Component
#ConfigurationProperties(prefix = "example")
public class NameProperties {
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
NameConfiguration.java
#Component
public class NameConfiguration {
#Autowired
NameProperties property;
public void getName(int index) {
System.out.println(property.getName().get(0));
}
}

Related

Getting null value from #configuration

I'm creating pojo class and store the application.properties variable but I'm getting null values
NOTE: need to access env from my Abstract class
POJO class
package mynt.xyz.c4.pushnotif.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
#Configuration("notificationEnvironment")
#ConfigurationProperties(prefix = "app.notif")
public class NotificationEnvironment {
private String key;
private String url;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Initializing class with #autowired
public abstract class NotificationBase {
#Autowired
NotificationEnvironment notificationEnvironment;
public void getEnv(){
system.out.println(notificationEnvironment.getKey()); // null value
}
}
concrete class that extend to my NotificationBaseClass
#Component
#Qualifier("androidNotification")
public class AndroidNotification extends NotificationBase implements Notification {
public AndroidNotification(String message, String title, String datalink, List<String> instanceIds) {
super(message, title, datalink, instanceIds);
}
AndroidNotification(){
super();
}
#Override
public void send() {
this.getEnv();
}
}
application.properties
app.notif.key=jkashdkjashd
app.notif.url=https/some.url
You can auto wire #Configuration class from #Configuration class
#Configuration class may reference the instance of any other #Configuration class using #Autowired. This works because the #Configuration classes themselves are instantiated and managed as individual Spring beans.
Make your class #Component and add prefix value in #ConfigurationProperties, like this. This works for me, hope this works for you as well.
#Component
#ConfigurationProperties(prefix = "app.notif")
public class NotificationEnvironment {
private String key;
private String url;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
You can use this properties like this:
#Component
public class NotificationBase {
private static NotificationEnvironment notificationEnvironment;
#Autowired
public NotificationBase(NotificationEnvironment notificationEnvironment){
this.notificationEnvironment = notificationEnvironment;
}
public static void getEnv(){
System.out.println(notificationEnvironment.getKey()); // null value
}
}
Here is the one of the concrete class definition as OP author mentioned.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ConcreteNotification extends NotificationBase {
#Autowired
public ConcreteNotification(NotificationEnvironment notificationEnvironment) {
super(notificationEnvironment);
}
}
updated NotificationBase as below
public abstract class NotificationBase {
NotificationEnvironment notificationEnvironment;
public NotificationBase(NotificationEnvironment notificationEnvironment) {
this.notificationEnvironment = notificationEnvironment;
}
public void getEnv(){
System.out.println(notificationEnvironment.getKey());
}
}
The controller class I am using to get configuration values
#RestController
public class ArticleCommentController {
#Autowired
ConcreteNotification concreteNotification;
#RequestMapping(value = "/health_check", method = RequestMethod.GET)
public void getDemo() {
concreteNotification.getEnv();
}
}
output:
jkashdkjashd

Use configuration properties in apache camel route

Is it possible to use concated strings in a apache camel route? Property placeholders work fine but concatation doesn't work.
If tried something like this but the route doesn't pass the data.
dependencies
"org.springframework.boot:spring-boot-starter:2.1.3.RELEASE",
"org.apache.camel:camel-jackson:2.23.1",
"org.apache.camel:camel-paho:2.23.1",
application.properties
a.b.property1=test
a.b.property2=test
RouteConfig
#Configuration
#ConfigurationProperties(prefix = "a")
public class RouteConfig{
private B b;
public B getB() {
return b;
}
public static class B {
private String property1;
private String property2;
public String getProperty1() {
return property1;
}
public String getProperty2() {
return property2;
}
}
}
#Component
public class Route extends RouteBuilder {
#Autowired
RouteConfig routeConfig;
#Override
public void configure() throws Exception {
from("paho://" + routeConfig.getB().getProperty1()).to(direct:foo)
}
}
Apache camel should build the route with a string which is build with concatination.

Spring: How to inject a Supplier<String> function as constructor parameter

I've coded this class:
#Component
public class AuditFactory {
private Supplier<String> auditIdSupplier;
public AuditFactory(Supplier<String> auditIdSupplier) {
this.auditIdSupplier = auditIdSupplier;
}
}
It's used as a dependency of a #Service class:
#Service
public class AuditService {
private AuditFactory auditFactory;
public AuditService(AuditFactory auditFactory) {
this.auditFactory = auditFactory;
}
}
How could I tell to Spring that injects a Supplier<String> when AuditFactory is injected?
EDIT
#Bean
public Supplier<String> auditIdSupplier(FrontOfficeProperties frontOfficeProperties) {
return () -> String.join(
"-",
frontOfficeProperties.getCpdId(),
frontOfficeProperties.getRedisAuditKeyPrefix(),
UUID.randomUUID().toString()
);
}
where FrontOfficeProperties is an #ConfigurationProperties annotated class.
below approach might help you to fix your issue.
also can you please share Supplier class as well.
#Component
public class AuditFactory {
private Supplier<String> auditIdSupplier;
public AuditFactory(Supplier<String> auditIdSupplier) {
this.auditIdSupplier = auditIdSupplier;
}
}
#Service
public class AuditService {
private AuditFactory auditFactory;
public AuditService(AuditFactory auditFactory) {
this.auditFactory = auditFactory;
}
}

Why are spring beans validated even if the condition says it should not be loaded into the context?

Given the example below, I would expect MyConfig.getSrvConfig() would not be called and therefore no validation would be executed on the returned object neither.
But for some reason the validation is executed and the test case fails. Is there anything wrong in this setup?
I know the test would pass if I have private MySrvConfigBean srvConfig not initialized at declaration - but I really don't want MySrvConfigBean to be a standalone class with a #ConfigurationProperties(prefix = "cfg.srvConfig") annotation.
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { TestCaseConfiguration.class })
public class ConditionalConfigValidationTest {
#Autowired
private ApplicationContext applicationContext;
#Test
public void test() {
assertNotNull(applicationContext);
assertFalse("srvConfig must NOT be in context", applicationContext.containsBean("srvConfig"));
}
#Configuration
#EnableConfigurationProperties(value = { MyConfig.class })
public static class TestCaseConfiguration {
}
#Component
#Validated
#ConfigurationProperties(prefix = "cfg")
public static class MyConfig {
private MySrvConfigBean srvConfig = new MySrvConfigBean();
#Bean
#Valid
#Conditional(MyCondition.class)
public MySrvConfigBean getSrvConfig() {
return srvConfig;
}
public static class MySrvConfigBean {
#NotNull
private String name;
public String getName() {
return name;
}
}
}
public static class MyCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
}
The reason we would like to have it this way is, because we then are able to structure configuration in code the same way as we have it in the YAML file, e.g.: (cfg and cfgA are the "root" objects for two different configuration hierarchies).
cfg:
srvConfig:
name: Dude
clientConfig:
xxx: true
yyy: Muster
cfgA:
aaaConfig:
bbb: false
ccc: Dundy
dddConfig:
fff: 3
It feels like the execution of the validation (triggered by #Valid on getSrvConfig()) is a bug in this case.
Apparently this is not supported and should be solved in a different way:
#Configuration
#Conditional(MyCondition.class)
#EnableConfigurationProperties(value = { MyConfig.class })
public static class TestCaseConfiguration {
}

#Configurable not working on Subclass

Take the following general abstract class:
#Configurable
public abstract class TestEntityRoot {
public abstract String print();
}
And a subclass:
#Configurable
public class TestEntity extends TestEntityRoot{
private TestEntityService testEntityService;
#Autowired
public void setTestEntityService(TestEntityService testEntityService) {
this.testEntityService = testEntityService;
}
#Override
public String print() {
return testEntityService.print();
}
}
When call controller:
#RestController
public class TestEntityController {
#GetMapping(name = "/test")
public String print() {
TestEntity entity = new TestEntity();
return entity.print();
}
}
everything ok. But if call like this:
#RestController
public class TestEntityController {
#GetMapping(name = "/test")
public String print() {
TestEntityRoot entity = new TestEntity();
return entity.print();
}
}
i get null pointer. Is it possible that second example work?
In the second case you create manually the class rather than using spring's bean. Autowire the bean instead. See
#RestController
public class TestEntityController {
#Autowired
private TestEntity entity
#GetMapping(name = "/test")
public String print() {
return entity.print();
}
}

Resources