I have a spring boot server app in my src/test folder that is configured to run with my test.properties.
Currently my properties looks like this:
server.port=9119
server.ssl.enabled=false
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.version=0.97
billing.engine.core.name=Patient_Responsibility
I want to retire server.port and point my server to get the port from billing.engine.port.
Is it possible to configure Spring to do this?
My spring app main class currently looks like this
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
#SpringBootApplication
public class MockServerApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
new SpringApplicationBuilder(MockServerApp.class)
.properties("spring.config.name:test")
.build()
.run(args);
}
}
you can use this code
#Component
public class ServerPortCustomizer
implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
#Value("${billing.engine.port}")
private String SERVERPORTNO;
#Override
public void customize(ConfigurableWebServerFactory factory) {
factory.setPort(SERVERPORTNO);
}
}
and also change your application.properties
#server.port=9119
billing.engine.port=9119
it's not a tested code.... I am writing this code based on my knowledge
Related
I created Spring project via Spring Initializr with project following struct:
I defined property in application.properties file :
my.prop=testvalue
I inject this value into MyClass as following :
#Component
class MyClass {
#Value("${my.prop}")
private String myProp;
public String getMyProp() {
return myProp;
}
}
ConfigBeans defined as following:
package com.example.propertiesdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ConfigBeans {
#Bean
public MyClass myLitoBean() {
return new MyClass();
}
}
PropertiesdemoApplication.java :
package com.example.propertiesdemo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(
ConfigBeans.class);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}
I am expecting that after executing line
System.out.println(myClass.getMyProp());
will be printed value of myprop defined in application.properties (i.e testvalue), but after running (via Netbeans IDE) I get output :
${my.prop}
What was missed / wromg in this code ? Thanks in advance
You are creating MyClass bean twice.
Using #component annotation
using #bean annotation in the config class (use method name lowerCamelCase i.e. in your case myClass())
Create bean only once using any one of the above.
You dont need to create an application context in the main method like this. The presented code is a kind of mixture of "traditional" spring and spring boot. So you're kind of bypassing all the goodies that spring boot offers, among which is automatic application.properties loading.
If you're using spring boot (there is a #SpringBootApplication annotation) then it will create everything by itself.
Usually it should be something like this
public static void main(String[] args) {
SpringApplication.run(PropertiesdemoApplication.class, args);
}
Right, as Navnath Adsul said, you need the bean to be created once, and also, since you are using Spring Boot, you need to raise the context using a special method
#SpringBootApplication
public class PropertiesdemoApplication implements CommandLineRunner {
// Inject Bean
#Autowired
private MyClass myClass;
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(PropertiesdemoApplication.class)
.run(args);
// or SpringApplication.run(PropertiesdemoApplication.class, args);
}
#Override
public void run(String[] args) throws Exception {
System.out.println(myClass.getMyProp());
}
}
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PropertiesdemoApplication.class, args);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}
I am working with #Configuration properties with spring boot version 2.4.2. Application start up seems to be fine but properties are not getting loaded as map. Please find the sample code in below snippets
ApisConfig.java
#Getter
#Setter
#ConfigurationProperties(prefix = "apis")
#Component
#ToString
public class ApisConfig {
private Map<String, String> apisMap =new HashMap<>();
public String getRouteDetails(String key){
return this.apisMap.get(key);
}
}
Below is the main application where spring boot is annotated
#ComponentScan(
basePackages = {"com.demo"})
#SpringBootApplication
#EnableConfigurationProperties(ApisConfig.class)
public class DemoApplication implements CommandLineRunner {
#Autowired
private ApisConfig apisConfig;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
apisConfig.getRouteDetails("qna");
}
}
Following is the properties file located under src/main/resources
apis.apisMap.qna=10.0.0.254
apis.apisMap.adapter=10.0.0.254
server.port=6165
Following are the tools I am using for building
Gradle
IntelliJ Idea
Spring boot 2.4.2
Any help is appreciated
I found out the solution for this. #AndyWilkinson Thank you for your pointer. Lombok was not set properly, because of which the apisMap is not getting picked properly. I have fixed it and started to work like a gem. I have added following dependencies to build.gradle file and started to work
annotationProcessor 'org.projectlombok:lombok'
I have a very simple Spring application, but I can't not get a System.out.println statement to print into the console.
This is the main app file where I am printing an env variable set in a .yml file
import path.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MainApplication {
#Autowired
private Config config;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MainApplication.class);
app.run();
}
public void run(String... args) throws Exception {
System.out.println("env: " + config.getEnv());
}
}
The configuration file looks like this:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties
public class Config {
private String env;
public void setEnv(String env) {
this.env = env;
}
public String getEnv() {
return this.env;
}
}
Finally the properties yml file
spring:
profiles.active: dev
h2:
console:
enabled: true
---
spring:
profiles: dev
env: dev
---
spring:
profiles: test
env: test
---
spring:
profiles: prod
env: prod
The Spring app builds a runs fine, however, I can't see the env variable to show in the terminal. I have seen examples of people using Controllers with a Request endpoint just to debug the environment variables in the browser. Is that the only option?
Couple of changes to your code, you don't need to use new keyword for starting spring application, you can directly use static run method
public static void main(String[] args) {
SpringApplication.run(MainApplication.class);
}
Second thing the run method in MainApplication will only execute if that class implements CommandLineRunner
#SpringBootApplication
public class MainApplication implements CommandLineRunner {
#Autowired
private Config config;
public static void main(String[] args) {
SpringApplication.run(MainApplication.class);
}
public void run(String... args) throws Exception {
System.out.println("env: " + config.getEnv());
}
}
I created a spring-boot 1.4.0 application and I would like to internationlize it using yaml file.
I created a class for loading the configuration from the yaml file like it is explained in the documentation here http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties.
I would like to create a test to check that my class has correctly loaded the properties from the yaml file.
If we keep the exemple from the documentation how to create a unit test that will load a yaml file (with a different name that application.yml) and check that the method getUsername() will return the value from the yaml file ?
Here is the code I have but still can't load the username :
#Component
#ConfigurationProperties(locations = "classpath:mylocalizedprops.yml", prefix="connection")
public class ConnectionProperties {
private String username;
// ... getters and setters
}
and the test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = Application.class)
public class InternationalizationTest {
#Autowired
private ConnectionProperties connectionProperties;
public void propsShouldBeNotNull() {
assertNotNull(connectionProperties);
}
public void userNameShouldBeCorrect() {
assertEquals(connectionProperties.getUsername(), expectedUserName);
}
}
I have failed the userNameShouldBeCorrect test. The file mylocalizedprops.yml is located in the src/main/resources folder of a Maven structured application.
I would consider this an integration test, not a unit-test because you are testing the interaction between various components. Regardless, here is how I would do it.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = YourApplication.class)
public class InternationalizationTests() {
#Autowired
ConnectionProperties connectionProperties;
#Test
public void testCorrectTranslationLoaded() {
Assert.assertEquals("english-username", connectionProperties.getUsername());
}
}
You can also create a test configuration if you would like to, which you can specify which translation to load. You would then need different classes to test different configurations. See the docs: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
Unit test can be done easily with Jmockit
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import mockit.Mock;
import mockit.MockUp;
import mockit.Mocked;
import mockit.Verifications;
class RuleApiApplicationTest {
#Mocked
private ConfigurableApplicationContext mockedContext;
#Test
void testApplicationRun() {
new MockUp<SpringApplication>() {
#Mock
public ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return mockedContext;
}
};
RuleApiApplication.main(new String[]{});
new Verifications() {{
SpringApplication.run(RuleApiApplication.class, new String[]{});
}};
}
}
I have a question, maybe simple, but I can not find out the solution.
I am using spring boot and added some annotation to the code like this:
#EnableEurekaClient
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
But in some other environment, for example, in production environment, we want to remove EurekaClient, but I do not want to manually remove it manually for each environment, instead, I want to use environment variable or command line parameter to control the behavior. I suppose to do this way:
#EnableEurekaClient(Enabled = {EnableEureka})
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Then I can easily start this application without touching the code.
Can anyone tell me if this is possible? If so, how can I do it?
Thanks
You would want to work with Spring Boot Profiles. Split out the #EnableEurekaClient to another #Configuration class and also add an #Profile("eureka-client") to the class. Then when starting up the application you can set a -Dspring.profiles.active=eureka-client for the environments other than production.
Example:
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
#Configuration
#EnableEurekaClient
#Profile("eureka-client")
public class EurekaClientConfiguration {
}
I prefer this method as you don't have to create an extra profile:
#Configuration
#EnableEurekaClient
#ConditionalOnProperty(name = "application.enabled", havingValue = "true", matchIfMissing = false)
public class EurekaClientConfiguration {
}