Java Spring: no take the variable into file-properties - java

In my repository there are file-properties with this var:
wizard.start.scriptNameAndroid=install-android.bat
This is a part of my file spring-businss.xml:
<bean id="wizardService" class="business.services.WizardServiceImpl">
<property name="nameFileAndroid" value="${wizard.start.scriptNameAndroid}"/>
</bean>
This is my class Java
public class WizardServiceImpl implements WizardService {
private static String nameFileAndroid="";
[...]
public String getNameFileAndroid() {
return nameFileAndroid;
}
public void setNameFileAndroid(String nameFileAndroid) {
this.nameFileAndroid = nameFileAndroid;
}
}
When i use the variable nameFileAndroid the program take always the value that i set into the class.
How can i do priority of file file-properties?

Why you don't Inject it using:
#Value("${wizard.start.scriptNameAndroid}")
private static String nameFileAndroid;
it will take value from your properties file.

If that variable is in .properties file you can refer to its value like this:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
#ComponentScan(basePackages = { "business.services.*" })
#PropertySource("classpath:file.properties")
public class WizardServiceImpl implements WizardService {
#Autowired
private Environment enviro;
private static String nameFileAndroid = enviro.getProperty("wizard.start.scriptNameAndroid");
}
Another way
#ComponentScan(basePackages = { "business.services.*" })
#PropertySource("classpath:file.properties")
public class WizardServiceImpl implements WizardService {
#Value("${wizard.start.scriptNameAndroid}")
private static String nameFileAndroid;
//Register bean to enable ${} value wiring
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Or if you still prefer XML way:
<context:property-placeholder location="resources/file.properties" />
Hope i helped. :)

Related

Parameter 0 of constructor in my class required a bean of my second class that could not be found

I know it's a problem that is been posted 100 times, but unfortunately I am getting a Defining Bean error in my Spring Boot Application and I really do not know why. I do not see my error from launch to finish since I am defining a bean.
I would appreciate any help.
I'm sure it's a stupid mistake which I just don't see
My error Code
Description:
Parameter 0 of constructor in com.example.demo.jwt.JwtSecretKey required a bean of type 'com.example.demo.jwt.JwtConfig' that could not be found.
Action:
Consider defining a bean of type 'com.example.demo.jwt.JwtConfig' in your configuration.
JwtSecretKey class
package com.example.demo.jwt;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.crypto.SecretKey;
#Configuration
public class JwtSecretKey {
private final JwtConfig jwtConfig;
#Autowired
public JwtSecretKey(JwtConfig jwtConfig) {
this.jwtConfig = jwtConfig;
}
#Bean
public SecretKey secretKey() {
return Keys.hmacShaKeyFor(jwtConfig.getSecretKey().getBytes());
}
}
JwtConfig class
package com.example.demo.jwt;
import com.google.common.net.HttpHeaders;
import org.springframework.boot.context.properties.ConfigurationProperties;
#ConfigurationProperties(prefix = "application.jwt")
public class JwtConfig {
private String secretKey;
private String tokenPrefix;
private Integer tokenExpirationAfterDays;
public JwtConfig() {}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getTokenPrefix() {
return tokenPrefix;
}
public void setTokenPrefix(String tokenPrefix) {
this.tokenPrefix = tokenPrefix;
}
public Integer getTokenExpirationAfterDays() {
return tokenExpirationAfterDays;
}
public void setTokenExpirationAfterDays(Integer tokenExpirationAfterDays) {
this.tokenExpirationAfterDays = tokenExpirationAfterDays;
}
Annotate your JwtConfig class with #Configuration
#Configuration
#ConfigurationProperties(prefix = "application.jwt")
public class JwtConfig {
See in Javadocs:
Annotation for externalized configuration. Add this to a class
definition or a #Bean method in a #Configuration class if you want to
bind and validate some external Properties (e.g. from a .properties
file).
Reference: https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/ConfigurationProperties.html

Loading a random class using reflection and have it register as a component in springboot

I have a random class in a random package that is loaded through reflection after the app launches, is there a way for it to be registered as a component under springboot and have annotations such as #Autowired and #Value etc work for that class.
It works when it is in the same package at launch time, but if introduce it thorough another jar at runtime (same package or not) it doesn't work.
Below are samples that don't work even if it is in the same jar. I can't change the app's configuration - it would defeat the "random package/random class" objective.
Code in Spring boot application package
package sample.app
#SpringBootApplication
public class Application {
public static void main(String[] args) {
// Code that starts app
//
//
try {
Thread.sleep(7000);
Class test = Class.forName("test.Test", true, Application.class.getClassLoader());
System.out.println(test.getMethod("getName").invoke(null)); //NPE
System.out.println(test.getMethod("getProfiles").invoke(null)); //NPE
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Test.java
package test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
#DependsOn("blaaaaaaaah")
#ComponentScan
public class Test {
#DependsOn("blaaaaaaaah")
public static String getName() {
return SpringGetter.instance.getApplicationName();
}
#DependsOn("blaaaaaaaah")
public static String[] getProfiles() {
String[] profiles = SpringGetter.instance.getEnv().getActiveProfiles();
if (profiles == null || profiles.length == 0) {
profiles = SpringGetter.instance.getEnv().getDefaultProfiles();
}
return profiles;
}
}
SpringGetter.java
package test;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component("blaaaaaaaah")
public class SpringGetter implements InitializingBean {
public static SpringGetter instance;
#Value("${spring.application.name}")
private String applicationName;
#Autowired
private Environment env;
public SpringGetter() {
System.out.println("consASFJEFWEFJWDNFWJVNJSBVJWNCJWBVJNVJNVJSNJSNCSDJVNSVJtruct");
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
public Environment getEnv() {
return env;
}
public void setEnv(Environment env) {
this.env = env;
}
#PostConstruct
public void setInstance() {
instance = this;
}
#Override
public void afterPropertiesSet() throws Exception {
instance = this;
}
}
EDIT:
I managed to dynamically create the SpringGetter class as part of the same package as the Application class(the one with the #SpringBootApplication). I got Test.java to point to that dynamic class and yet no luck.
To simply inject fields into a POJO as if it were a Spring-managed bean, you can use something like the following:
#Component
public class BeanInitializer implements ApplicationContextAware {
private AutowireCapableBeanFactory beanFactory;
#Override
public void setApplicationContext(final ApplicationContext applicationContext) {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
public void initializeObject(Object pojo) {
beanFactory.autowireBean(pojo);
}
}
Note, however, that this only injects fields marked as #Autowired or #Injected. It does not create proxies that honor method interception strategies based on e.g. #Transactional, #Async, etc.
If you're using Spring 5, have a look at the registerBean() method from GenericApplicationContext. You can find an example here: https://www.baeldung.com/spring-5-functional-beans
The issue in your Test class may also be that you're not loading the Spring Boot context from the main class. You can use the SpringBootTest annotation for this.

Polymorphic configuration properties in Spring Boot

I would like to use polymorphic configuration properties on Spring, using Spring's #ConfigurationProperties annotation.
Suppose we have the following POJO classes.
public class Base {
private String sharedProperty;
public String getSharedProperty() {
return sharedProperty;
}
public String setSharedProperty(String sharedProperty) {
this.sharedProperty = sharedProperty;
}
}
public class Foo extends Base {
private String fooProperty;
public String getFooProperty() {
return fooProperty;
}
public String setFooProperty(String sharedProperty) {
this. fooProperty = fooProperty;
}
}
public class Bar extends Base {
private String barProperty;
public String getSharedProperty() {
return sharedProperty;
}
public String setBarProperty(String barProperty) {
this.barProperty = barProperty;
}
}
And the configuration properties class,
#Component
#ConfigurationProperties(prefix = "playground")
public class SomeConfigurationProperties {
private List<Base> mixed;
public List<Base> getMixed() {
return mixed;
}
public void setMixed(List<Base> mixed) {
this.mixed = mixed;
}
}
And the application.yml file,
playground:
mixed:
- shared-property: "shared prop"
foo-property: "foo prop"
- shared-property: "shared prop"
bar-property: "bar prop"
However, with this configuration, Spring initializes the #ConfigurationProperties-annotated class with the list of Base objects, instead of their subclasses. That is, actually, an expected behavior (due to security concerns).
Is there a way to enforce the behavior of SnakeYAML to use subclasses, or implement any kind of custom deserialization provider?
Although it is possible to implement custom PropertySources and/or ConversionService, a custom deserialization provider is not necessary.
Spring has no issues binding the same properties to multiple beans. The reason your implementation is not working is because you are only registering one bean with the ApplicationContext with the #Component annotation on the base class. This is telling the component scanner that there is only one singleton of type Base. Because Foo and Bar are not registered as beans, they won't be bound to.
If the only reason you are looking at making these polymorphic is to share property name prefixes in SnakeYAML based config, then you actually do not need to introduce the polymorphic relationship, and can bind to shared properties by a common field name in different classes.
There are many ways to implement what you are asking for however in a polymorphic way, here are a few of the most straight forward simple ones:
Self declaring Polymorphic ConfigurationProperties singleton beans
Instead of applying the #ConfigurationProperties and #Component annotations on the base class, apply them on the concrete classes, with the same property name prefix. This wouldn't be my preferred approach, as each bean would not be conditional on their properties being set, however it may suit your needs. Depending on if your Spring Configuration allows properties to be reloaded, Spring will maintain the bindings on all of the beans.
Note: As of IntelliJ Idea 2018.3, an inspection profile was added to identify duplicate prefix keys as an error. You may want to ignore this, or suppress the warnings.
I tested the following successfully:
Base.java
package sample;
public class Base {
private String sharedProperty;
public String getSharedProperty() {
return sharedProperty;
}
public void setSharedProperty(String sharedProperty) {
this.sharedProperty = sharedProperty;
}
}
Foo.java
package sample;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Component
#ConfigurationProperties("playground")
public class Foo extends Base {
private String fooProperty;
public String getFooProperty() {
return fooProperty;
}
public void setFooProperty(String fooProperty) {
this.fooProperty = fooProperty;
}
}
Bar.java
package sample;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Component
#ConfigurationProperties("playground")
public class Bar extends Base {
private String barProperty;
public String getBarProperty() {
return barProperty;
}
public void setBarProperty(String barProperty) {
this.barProperty = barProperty;
}
}
application.yml
playground:
shared-property: "shared prop"
foo-property: "foo prop"
bar-property: "bar prop"
SampleAppTest.java
package sample;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
#SpringBootTest
public class SampleAppTest {
#Autowired
public Environment environment;
#Test
public void test(#Autowired Bar bar, #Autowired Foo foo) {
assertEquals("shared prop", bar.getSharedProperty());
assertEquals("shared prop", foo.getSharedProperty());
assertEquals("bar prop", bar.getBarProperty());
assertEquals("foo prop", foo.getFooProperty());
}
#Test
public void testSuper(#Autowired List<Base> props) {
assertEquals(2, props.size());
}
}
Polymorphic ConfigurationProperties beans conditional on properties
You may not want certain concrete implementations to be instantiated if their specific properties are missing. Furthermore, you may not want to couple the #ConfigurationProperties and #Component annotations to each concrete class. This implementation constructs the ConfigurationProperties beans via a Spring #Configuration bean. The configuration bean ensures they are only constructed conditionally via a property existence check. This implementation also creates a bean of concrete type Base if none of the other Base beans meet conditions and the shared properties exist. The same unit test from the previous example is used here and passes:
Base.java
package sample;
public class Base {
private String sharedProperty;
public String getSharedProperty() {
return sharedProperty;
}
public void setSharedProperty(String sharedProperty) {
this.sharedProperty = sharedProperty;
}
}
Foo.java
package sample;
public class Foo extends Base {
private String fooProperty;
public String getFooProperty() {
return fooProperty;
}
public void setFooProperty(String fooProperty) {
this.fooProperty = fooProperty;
}
}
Bar.java
package sample;
public class Bar extends Base {
private String barProperty;
public String getBarProperty() {
return barProperty;
}
public void setBarProperty(String barProperty) {
this.barProperty = barProperty;
}
}
SampleConfiguration.java
package sample;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class SampleConfiguration {
#Bean
#ConfigurationProperties("playground")
#ConditionalOnProperty("playground.foo-property")
public Foo foo() {
return new Foo();
}
#Bean
#ConfigurationProperties("playground")
#ConditionalOnProperty("playground.bar-property")
public Bar bar() {
return new Bar();
}
#Bean
#ConfigurationProperties("playground")
#ConditionalOnProperty("playground.shared-property")
#ConditionalOnMissingBean(Base.class)
public Base base() {
return new Base();
}
}
application.yml
playground:
shared-property: "shared prop"
foo-property: "foo prop"
bar-property: "bar prop"
SampleAppTest.java
package sample;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
#SpringBootTest
public class SampleAppTest {
#Autowired
public Environment environment;
#Test
public void test(#Autowired Bar bar, #Autowired Foo foo) {
assertEquals("shared prop", bar.getSharedProperty());
assertEquals("shared prop", foo.getSharedProperty());
assertEquals("bar prop", bar.getBarProperty());
assertEquals("foo prop", foo.getFooProperty());
}
#Test
public void testSuper(#Autowired List<Base> props) {
assertEquals(2, props.size());
}
}

How to use #PropertySource with Java Spring 4.0.4?

I would like to add the source of database.properties which is in ProjectName/src/database.properties to AppConfig.class which is in ProjectName/src/device/spring/configaccording to https://www.journaldev.com/17053/spring-jdbctemplate-example
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import tekranchecklist.model.*;
#Configuration
#ComponentScan("device.spring.dao","device.model","device.spring.config","device.Main")
public class AppConfig {
#Autowired
Environment environment;
private final String URL = "URL";
private final String USER = "root";
private final String DRIVER = "DRIVER";
private final String PASSWORD = "PASSWORD";
#Bean
DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl(environment.getProperty(URL));
driverManagerDataSource.setUsername(environment.getProperty(USER));
driverManagerDataSource.setPassword(environment.getProperty(PASSWORD));
driverManagerDataSource.setDriverClassName(environment.getProperty(DRIVER));
return driverManagerDataSource;
}
}
I tried to use #PropertySource("classpath:database.properties") but it is syntax error that: class, interface or enum expected. Can someone help me how I should add my .properties file path with #PropertySource?
#PropertySource is an annotation that can be used only on types, that is interface, class, enum :
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Repeatable(PropertySources.class)
public #interface PropertySource {...}
This class, interface or enum expected message is a compilation error that means that you specified the annotation on a target that doesn't match to a type.
So move it at the correct place :
#PropertySource("classpath:database.properties")
public class AppConfig {
....
}
You can use #PropertySource with either #Value or Environment as shown below.
Assuming this is your application property file.
app.value.example=v1
app.environment.example=e1
Using #PropertySource with #Value
#Configuration
#PropertySource("classpath:application.properties")
public class ApplicationContig {
#Value("${app.value.example:defaultValueCanBeHere}")
private String propertyValue;
public void usePropertyValue() {
// You can use it here
}
}
Using #PropertySource with Environment
#Configuration
#PropertySource("classpath:application.properties")
public class ApplicationContig {
#Autowired
private Environment environmentValue;
private void useEnvironmentValue() {
String value = environmentValue.getProperty("app.environment.example");
// You can then use it here.
}
}
With Spring >= 4
#Configuration
#PropertySources({
#PropertySource(value = "classpath:application.properties"),
#PropertySource(value = "classpath:another.properties"),
#PropertySource(value = "classpath:missing-file.properties",
ignoreResourceNotFound = true)})
public class ApplicationContig {
// You can either use #Value or Environment as demonstrated above
}
I hope this will help.

Order of component scanning in spring

Am new to spring, had defined the ApplicaionConfig.java there I placed the property file details.
package com.rao.first;
//
// import statements
//
#Configuration
#ComponentScan(basePackageClasses = { ApplicationConfig.class }, basePackages = { "com.rao.first" })
#PropertySources({
#PropertySource("file:${webapp.root}/resources/config/application.properties"),
#PropertySource(value = "file:${conf.dir}/someother.properties", ignoreResourceNotFound = true) })
class ApplicationConfig
{
#Bean
ServletContextListener logbackConfigListener()
{
return new LogbackConfigListener();
}
}
and defined some controller classes.
package com.rao.first.controller;
//
// import statements
//
#Controller
#RequestMapping(value = "/first")
public class FirstController
{
private String viewerUrl;
#Inject
public FirstController(Environment env)
{
this.viewerUrl = env.getProperty("property1");
}
//
//
}
But here first controller is executing, after that ApplicaitonConfig is executing, so unable to get the data from property file.
And spring-servlet.xml file configurations are
<context:component-scan base-package="com.rao.first.view" />
<context:component-scan base-package="com.rao.controller.security" />
<context:component-scan base-package="com.rao.controller" />
Please guide me how can set order of execution?
You could use org.springframework.context.annotation.PropertySource annotation to retrieve values from a properties file.
So your controller class could be like following:
package com.rao.first.controller;
import org.springframework.context.annotation.PropertySource;
//
// import statements
//
#Controller
#RequestMapping(value = "/first")
#PropertySource("classpath:/com/rao/app.properties")
public class FirstController
{
private String viewerUrl;
#Autowired
Environment env;
public FirstController()
{
this.viewerUrl = env.getProperty("property1");
}
//
//
}
I hope it helps you, bye.

Categories

Resources