I am updating a web app from Spring Boot 2.2.4 to 2.5.6 and have used Open Rewrite to handle the tedium. The run configuration in IntelliJ has spring-boot:run -Dspring.profiles.active=local -f pom.xml in the command line (this has been working with 2.2.4). After adding a try/catch to main, to actually learn why I kept getting exit code 1 with no additional info, I found java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.profiles.active' in value "classpath:application-${spring.profiles.active}.properties" to be the root issue.
Apparently passing local on the command line for spring.profiles.active is now ignored… So, I added it to application.yml which gives me a message about how it is invalid to use spring.profiles.active. I found that the currently active profile should now be in config.activate.on-profile.active so I switched to that and then did a project wide search for spring.profiles.active and replaced every single instance with config.activate.on-profile.active.
I ran the project again and again got the message that it could resolve the placeholder spring.profiles.active! I can't for the life of me figure out where that placeholder is coming from since it doesn't exist anywhere in the project now according to IntelliJ, not even in the ReadMe file!
Is there some secret place I need to look to purge this old placeholder from existence?
I ran into the same issue and found a link to a github issue where a workaround was provided.
Create a class:
public class JunitProfileResolver implements ActiveProfilesResolver {
private static final String PROFILE_JUNIT = "test";
#Override
public String[] resolve(Class<?> testClass) {
System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, PROFILE_JUNIT);
return new String[] { PROFILE_JUNIT };
}
}
And use it like:
#ActiveProfiles(profiles = "test", resolver = JunitProfileResolver.class)
public class MyTest {
For me this solves the problem.
Related
I used to complete sample from Spring Data...
It works well.
I added application.properties
#spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.url=jdbc:h2:file:./h2/demo
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=wrong
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
I worked (apparently on first run it creates the database with whatever password defined).
When I changed the password to newWrong it started failing as expected (so I verified it's checking password).
Now I changed the property file to contain
spring.datasource.password=#{systemProperties['pass']}
and I changed the AccessingDataJpaApplication's main to:
public static void main(String[] args) {
System.setProperty("pass", "wrong" );
SpringApplication.run(AccessingDataJpaApplication.class);
}
and it is not working - still complaining about the password.
On the other hand, when I added
#Value("${bar}")
String foo;
and defined in application properties (and used wrong for password to prevent failing)
bar=#{systemProperties['pass']}
this statement in Application class
System.out.println("foo: " + foo);
prints foo: wrong.
Why the same is not working for spring.datasource.password property?
This might not be the exact answer to your question, but I believe it is the answer to what you are trying to solve.
You can simply pass the password to the app when you launch it on the command line by appending a -Dspring.datasource.password=wrong to the command. You can do that with any spring property.
If you are running from and IDE, you can edit the run configuration, there should be a field for VM Options where you can pass that in.
That would be the canonical way of handling in Spring.
Delete the line or change the path(example /h2/demo1).
spring.datasource.url=jdbc:h2:file:./h2/demo
because the last configuration is storage on this file.
Just tried with
spring.datasource.password=${pass}
and it works correctly.
You can also use environment variables of format SPRING_DATASOURCE_PASSWORD to define these properties. Spring Boot will resolve them without any addition to application configuration.
Ref: https://docs.spring.io/spring-boot/docs/2.2.3.RELEASE/reference/htmlsingle/#boot-features-external-config-application-property-files
I've just installed the latest version of SonarLint and launched a full SonarLint analysis on the code of our new trainee who has put some non-static non-injected members in a Spring singleton just like in this example :
#Controller
public class HelloWorld {
private String name = null;
#RequestMapping("/greet", method = GET)
public String greet(String greetee) {
if (greetee != null) {
this.name = greetee;
}
return "Hello " + this.name; // if greetee is null, you see the previous user's data
}
}
https://rules.sonarsource.com/java/tag/spring/RSPEC-3749
So I was hoping that SonarLint would detect it, but no (I have other advices, but nothing about this).
Is this rule part of a special set which need to be activated in some conf somewhere ?
As you intuitively thought, rule squid:S3749 is not part of the quality profile by default (usually called SonarWay). It consequently won't be executed with a fresh install of SonarLint, without proper configuration.
From there, you have two options to enable the rule:
Connect SonarLint to a SonarQube instance or SonarCloud, which would allow you to configure and synchronize quality profiles for all your projects automatically, executing the rules which are expected for each projects
With latest versions of SonarLint (I tried with version 4.1 for eclipse), you should be able to enable rules directly through the plugin configuration, but this won't be shared with others working on the project.
Note that unfortunately, there is currently no way on https://rules.sonarsource.com/ to see the information about quality profiles (I'm making the internal feedback right now in order to maybe fix this in the future)
Problem:
I have 3 parts in the software:
Client A service
Client B service
Target C service
I want to connect to C from A and B
I wrote a library with following setup:
/src/main/java/pkg.../TargetConnector.java
/src/main/java/pkg.../TargetConfig.java
/src/main/resources/application-dev.properties
/src/main/resources/application-tst.properties
/src/main/resources/application-prd.properties
My clients A and B both have there own sources and properties:
/src/main/java/pkg.../Client{A/B}Service.java
/src/main/java/pkg.../Client{A/B}Config.java
/src/main/resources/application-dev.properties
/src/main/resources/application-tst.properties
/src/main/resources/application-prd.properties
The properties of the Connector contains some login info for the service e.g.
target.url=https://....
target.usr=blablabla
target.key=mySHAkey
which is used in the TargetConfig to preconfigure the Connector e.g.
#Value("target.url")
String url;
#Value("target.usr")
String usr;
#Value("target.key")
String key;
#Bean
public TargetConnector connector() {
return new TargetConnector(url, usr, key);
}
Now when I use the connector jar in the client I can find the configuration via packagescan. The connector class is loaded but the problem is that it does not load the properties files.
Research
I found that multiple property files cannot have the same name (e.g. clients application-{profile}.properties clashes with the one from the connector), so I tried to rename application-{profile}.properties of the targetConnector to application-connector-{profile}.properties.
The properties whoever still do not get loaded, (which makes sense since I do not have a e.g connector-dev profile but my profile is simply named dev).
Furthermore, even if I try to explicitly load one of the property files from the connector with:
#PropertySource({"classpath*:application-connector-dev.properties"})
it cannot be found
Question
My question is actually 3 tiered:
How can I load a property file in a dependency jar at all?
How can I load the profiled version of the property file if the the properties file has a different name than application.properties? e.g. application-connector.properties
How can i combine the answers from question 1 and 2 to load the profiled version of the property in the jar?
If further explanation is needed, please ask.
Answer
I went for an approach as given in the accepted answer.
I Just created 3 configs for the dev, tst, prd profiles containing the values needed and annotated the config files with the correct profiles.
You are using #Configuration annotated class. Maybe you can have one per profile. Here you are an example:
#Configuration
#Profile("profileA")
#PropertySource({"classpath:application-profileA.properties"})
public class ConfigurationProfileA{
#Value("${target.url}")
String url;
#Value("${target.usr}")
String usr;
#Value("${target.key}")
String key;
#Bean
public TargetConnector connector() {
return new TargetConnector(url, usr, key);
}
}
Do the same for profile B (maybe you can structure this better but the key points here are the annotation #Profile("") and #PropertySource(""))
Once you have your config class, Spring will use the Configuration class you want by just filling -spring.profiles.active=profileA (or the name of the profile you have written in the #Profile("") annotation)
I think there is a typo in this line #PropertySource({"classpath*:application-connector-dev.properties"})
Please check by removing the asterik.
In order to run with a specific profile, you can run with option -spring.profiles.active=dev for example
If you don’t run with a profile, it will load the default profile in application.properties that you don’t seem to have.
Furthermore, an advice would be to always have an application.properties and put in it the common properties and the default values that you would override in other properties files.
Other mistake is how you assign properties with #Value annotation, you need to use #Value("${PROPERTY_FROM_PROPERTIES_FILE}")
I am trying to get gwt-test-utils to work. I set up the project in the following way:
src/main/java : all the java source code
src/test/java : the test source code
src/test/resources : resource files for the tests
I am building my project with gradle and eclipse. Gradle uses these directories correctly by default and I added all three of them as source directories to Eclipse.
I have successfully built and run the project and was able to execute some plain old JUnit tests as well as a GWTTestCase, so I think I set up the project and its dependencies correctly.
Now I wanted to use gwt-test-utils for some more advanced integration tests. To do so I did the following:
Add the gwt-test-utils and gwt-test-utils-csv to my dependencies
gwtTestUtilsVersion = '0.45'
testCompile group:'com.googlecode.gwt-test-utils', name:'gwt-test-utils', version:gwtTestUtilsVersion
testCompile group:'com.googlecode.gwt-test-utils', name:'gwt-test-utils-csv', version:gwtTestUtilsVersion
Add a gwt-test-utils.properties file to the directory src/test/resources/META-INF with the following content:
path/to/my/module = gwt-module
Added a class that extends GwtCsvTest to a package in the src/test/java directory. It is modeled after the second example in HowToWriteCsvScenario from the gwt-test-utils project wiki, replacing occurrence of their example classes with mine. It looks like this
#CsvDirectory(value = "gwtTests")
public class LoginLogoutTest extends GwtCsvTest
{
#Mock
private MainServiceAsync mainService;
private AppController appController = new AppController();
#CsvMethod
public void initApp()
{
appController.onModuleLoad();
}
#Before
public void setup()
{
GwtFinder.registerNodeFinder("myApp", new NodeObjectFinder()
{
#Override
public Object find(Node node)
{
return csvRunner.getNodeValue(appController, node);
}
});
GwtFinder.registerNodeFinder("loginView", new NodeObjectFinder()
{
#Override
public Object find(Node node)
{
return csvRunner.getNodeValue(appController.getRootPresenter().getCurrentlyActiveSubPresenters().iterator().next().getView(), node);
}
});
addGwtCreateHandler(createRemoteServiceCreateHandler());
}
}
added a csv-file for configuring the test to src/test/resources/gwtTests with the following content
start
initApp
assertExist;/loginView/emailTextBox
I tried executing it via the Eclipse's Run As > JUnit Test and indirectly via gradle build (which executes all the test cases, not just this one). Both lead to the same error:
ERROR GwtTreeLogger Unable to find type 'myPackage.client.AppController'
ERROR GwtTreeLogger Hint: Check that the type name 'myPackage.client.AppController' is really what you meant
ERROR GwtTreeLogger Hint: Check that your classpath includes all required source roots
The AppController class is the entry-point configured in the module I configured in gwt-test-utils.properties, which makes me think that configuration works correctly and the rest of the setup (dependencies and all) work as well.
In an earlier version I used the same file as a subclass of GWTTestCase and created an AppController instance in the same way. That worked, so I'm pretty sure the class path is setup correctly to include it as well. I also tried changing it back to the previous version just now and it still works.
I have no clue why the class is not found. Is there anything gwt-test-utils does differently which means I need to specifically set the class path for it? Otherwise it should just work, since both gradle and eclipse know about all the relevant source folders and dependencies.
I've got a problem running a batch job on my server, whereas it runs fine from Eclipse on my development workstation.
I've got my Spring environment set up using Roo, made an entity, and make a batch that does some work, and test it well on my develompent box. I initialize my context and do the work, but when I run my batch on the server, the context isn't initialized properly. Here's the code:
public class TestBatch {
private static ApplicationContext context;
#SuppressWarnings("unchecked")
public static void main(final String[] args) {
context = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");
try {
#SuppressWarnings("unused")
TestBatch app = new TestBatch();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void TestBatch() { /** Do Something using the context **/ }
}
And here's the log and exception:
2010-02-16 11:54:16,072 [main] INFO org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#6037fb1e: startup date [Tue Feb 16 11:54:16 CET 2010]; root of context hierarchy
Exception in thread "main" java.lang.ExceptionInInitializerError
at org.springframework.context.support.AbstractRefreshableApplicationContext.createBeanFactory(AbstractRefreshableApplicationContext.java:194)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:127)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:458)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:388)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at tld.mydomain.myproject.batch.TestBatch.main(TestBatch.java:51)
Caused by: java.lang.NullPointerException
at org.springframework.beans.factory.support.DefaultListableBeanFactory.<clinit>(DefaultListableBeanFactory.java:103)
... 7 more
Any idea or hints as to what's going on? My classpath is set to $PROJECTHOME/target/classes, and all my dependencies are in $PROJECTHOME/target/lib, and I execute using "export CLASSPATH=$PROJECTHOME/target/classes; java -Djava.endorsed.dirs=$PROJECTHOME/target/lib tld.mydomain.myproject.batch.TestBatch"
Is there anything in my setup that looks very wrong? When I run this from Eclipse, no problems, but when I deploy it on the server where I want to run it and run it as described above, I get this problem. Because it runs from Eclipse, I believe my config files are all right, but how can I debug what's causing this? Perhaps I have some config errors or a mismatch between the server and the development workstation after all? Or is this a really weird way of saying file not found, and if so, how do I make sure it finds the correct file??
I'm really looking forward to hearing your suggestions as to how to tackle this problem.
Cheers
Nik
The cause of problem is -Djava.endorsed.dirs=$PROJECTHOME/target/lib
org.springframework.beans.factory.support.DefaultListableBeanFactory contains the following code:
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
try {
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider"); //Line 103
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
}
}
It causes a NullPointerException, because getClassLoader() returns null when class is loaded via -Djava.endorsed.dirs. From javadoc:
Some implementations may use null to represent the bootstrap class loader.
So, use -classpath (with explicit specification of all jars) instead of -Djava.endorsed.dirs
Exception in thread "main" java.lang.ExceptionInInitializerError is occurs while adding User Library. I faced same problem in Hibernate and Spring as well. So i removed User Library say "Spring" then i add jars manually it work perfectly.
In Eclipse:
If you are using the spring jars as user library(Say SpringLib), see if the user library for spring is added(or checked) as System Library(added to the boot class path). If yes, remove the check mark.`
Just add the jars to referenced libraries and not to user library. It worked for me!