Spring Boot case sensitive resolving properties from program arguments - java

I am trying to run a Spring boot application on my local machine. When I use the following syntax for a property it resolves well:
username: ${project.db.user}
However the following raises an exception:
username: ${PROJECT_DB_USER}
Is there any way to use uppercase here? My CI/CD pipelines defines all its variables with uppercase

I've had similar problems, and from what I've understood, since springBoot v2.1, the application.properties files don't handle environement variables well. The solution is to use Spring Profiles.
You need to add as many .properties files as you have environments, like so :
application.properties
application-staging.properties
application-prod.properties
If you have a staging and prod profiles. The .properties of the profile overrides the basic application.properties, so be sure not to forget anything in each file !
There may be other solutions as well.
You can set the profiles using various methods, in Spring boot, with Maven (sorry, the only one I'm familiar with) you can simply add it to the pom.xml like this :
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>staging</profile>
</profiles>
</configuration>
</plugin>

Related

Inject property value from settings.xml during test profile run

I added a new functionality to my service where I now consume messages from rabbitMq. This works great and pretty much right out of the box with Spring Boot.
However, in order to not add the credentials to source control, I have been trying to inject the password from my user's settings.xml. This works as intended when I stand up the service locally with its default/production profile, but it does not when I run the test suite (test profile).
Below is an example of my settings.xml:
<settings
...
<profiles>
<profile>
<id>inject-properties</id>
<properties>
<prod.rabbit.pwd>someProdPwd</prod.rabbit.pwd>
<test.rabbit.pwd>someTestPwd</test.rabbit.pwd>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>inject-properties</activeProfile>
</activeProfiles>
</settings>
I run mvn help:active-profiles to validate it activates:
The following profiles are active:
- inject-properties (source: external)
- package (source: com.myservice:myservice:1.16.0-SNAPSHOT)
Then, in my application.properties I define the property as follows:
spring.rabbitmq.password=#prod.rabbit.pwd#
I stand up the service, and I can see the property being replaced by the value in settings.xml, so that part looks good.
Then, in my application-test.properties, I have:
spring.rabbitmq.password=#test.rabbit.pwd#
But when I proceed to run my tests, that does not work as it did before. When the rabbit bean is instantiated by the spring boot context builder, it passes the literal value #test.rabbit.pwd#, which fails authentication and causes the service not to stand up/test not to run.
Anyone ever run into this weird behavior? I found this question, which is pretty much the same issue I am having from a while back, but it did not really have a solution. Replace property placeholders in spring profile-specific properties file

Change CodeStar Spring MVC project to Spring Boot

I have a Spring Boot project that works perfectly when run in IDE. I would like to run this via AWS CodeStar. Unfortunately, the default Spring template created by CodeStar uses Spring MVC.
I cannot just overwrite the default Spring MVC project with my Spring Boot project (it doesn't work). I can copy some of my resources to the MVC project, for example index.html and that works. But then features like Thymeleaf don't work. For this and other reasons, I would like to change the provided Spring MVC into the Spring Boot structure I already have.
I followed the instructions here: https://www.baeldung.com/spring-boot-migration
Unfortunately, this doesn't help. I can create Application Entry Point and add Spring Boot dependencies without the app breaking. But when I remove the default dependencies or the configuration associated with the MVC, the app breaks. When trying to reach the URL, I get a 404 error with description:
The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
Debugging this error message (e.g. https://www.codejava.net/java-ee/servlet/solved-tomcat-error-http-status-404-not-found) didn't help.
The message seems like it's connected to the web resource. I have my web resources in folder resources as well as webapp/resources. And Spring Boot doesn't need any location configuration, right? It uses this location by default.
Can somebody tell me what things to remove and what to add to be able to use my existing Spring Boot project?
EDIT:
This is a link to a default template for AWS CodeStar Spring web application: https://github.com/JanHorcicka/AWS-codestar-template
And this is my Spring Boot project structure:
I realize that you indicated that previously you tried to use your Spring Boot project with some modifications without success, but I think it could be actually a possibility to successfully deploy your application on AWS CodeStar, and it will be my advice.
I also realized that in your screenshot you included several of the required artifacts and classes, but please, double check that you followed these steps when you deployed your application to AWS CodeStar.
Let's start with a pristine version of your Spring Boot project running locally, without any modification, and then, perform the following changes.
First, as indicated in the GitHub link you shared, be sure that you include the following files in your project. They are required for the deployment infrastructure of AWS:
appspec.yml
buildspec.yml
template.yml
template-configuration.json
The whole scripts directory
Please, adapt any necessary configuration to your specific needs, especially, template-configuration.json.
Then, perform the following modifications in your pom.xml. Some of them are required for Spring Boot to work as a traditional deployment and others are required by the deployment in AWS CodeStar.
Be sure that you indicate packaging as war:
<packaging>war</packaging>
To ensure that the embedded servlet container does not interfere with the Tomcat to which the war file is deployed, either mark the Tomcat dependency as being provided as suggested in the above-mentioned documentation:
<dependencies>
<!-- … -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- … -->
</dependencies>
Or exclude the Tomcat dependency in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
If necessary, apply this exclusion using some kind of profile that allows you to boot Spring Boot locally and in an external servlet container at the same time.
Next, parameterize the maven war plugin to conform to the AWS CodeStar deployment needs:
<build>
<pluginManagement>
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
<warName>ROOT</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- ... -->
<plugins>
</pluginManagement>
</build>
I do not consider it necessary, but just to avoid any kind of problem, adjust the name of your final build:
<finalName>ROOT</finalName>
Lastly, as also indicated in the Spring documentation, be sure that your MyProjectApplication - I assume this class is your main entry point subclass SpringBootServletInitializer and override the configure accordingly, something like:
#SpringBootApplication
public class MyProjectApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyProjectApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyProjectApplication.class, args);
}
}
Please, feel free to adapt the class to your specific use case.
With this setup, try to deploy your application and see if it works: perhaps you can find some kind of library dependencies problem, but I think for the most part it should work fine.
At a first step, you can try to deploy locally the version of the application you will later deploy to AWS CodeStar following the instructions you provided in your project template, basically, once configured with the necessary changes described in the answer, by running:
mvn clean package
And deploying the generated war on your local tomcat environment. Please, be aware that probably the ROOT application already exists in a standard tomcat installation (you can verify it by inspecting the webapps folder): you can override that war file.
For local testing you can even choose a different application name (configuring build.finalName and the warName in your pom.xml file): the important thing is verify if locally the application runs successfully.
If you prefer to, you can choose to deploy the app directly to AWS CodeStar and inspect the logs later it necessary.
In any case, please, pay attention on two things: on one hand, if you have any absolute path configured in your application, it can be the cause of the 404 issue you mention in the comments. Be aware that your application will be deployed in Tomcat with context root '/'.
On the other hand, review how you configured your database access.
Probably you used application.properties and it is fine, but please, be aware that when employing the application the database must be reachable: perhaps Spring is unable to create the necessary datasources, and the persistence manager or related stuff associated with and, as a consequence, the application is not starting. Again, it may be the reason of the 404 error code.
To simplify database connectivity, for testing, at first glance, I recommend you to use simple properties for configuring your datasource, namely the driver class, connection string, username and password. If that setup works properly, you can later enable JNDI or what deemed necessary.
Remember that if you need to change your context name and/or define a datasource pool in Tomcat you can place a context.xml file under a META-INF directory in your web app root path.
This context.xml should look like something similar to:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
<Resource name="jdbc/myDS"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
url="jdbc:mysql://localhost:3306/myds"
driverClassName="com.mysql.jdbc.Driver"
username="root"
password="secret"
/>
</Context>

SpringBoot "not an entity"

I am new to Hibernate and SpringBoot. My projects deals with a search engine that is composed of 2 independent modules + 1 base module common to both (where the IndexSetup class resides).
There is one module for indexing (JavaFx) and the other one for searching via the web browser (Spring Boot).
The indexing module involves an "IndexSetup" class that has the details on how / what should be indexed :
#Entity
#Table(name = "IndexSetups")
#Access(AccessType.PROPERTY)
public class IndexSetup {
private final SimpleIntegerProperty id = new SimpleIntegerProperty();
#Id
#GeneratedValue(strategy = GenerationType.AUTO) // For H2 AUTO is required to auto increment the id
public int getId() {
return id.get();
}
//... other properties, getters and setters
}
So it works great, the data is indexed and can be retrieved via a search method within the indexing module.
However when I run the Spring Boot server and do the same search I get
java.lang.IllegalArgumentException: Not an entity: class my.package.IndexSetup
By the way there is no build error, and before the modules were parts of a parent pom project, they were in the same project with the server class in a subfolder, and it worked. I decided to separate them for convenience during developpment and to offer two independent modules in production.
So why did it work when everything was under the same Netbeans project and now that the modules are in 2 different subfolders (but in the same group id package "my.package") I get this "Not an entity" and what should I do to solve this, where should I look at ?
Please note : I already tried this without success ("null pointer exception, cannot load the database").
Edit 1:
I also tried to add #EntityScan following this but I still get Not an entity: class my.package.IndexSetup :
#SpringBootApplication
#EntityScan( basePackages = {"my.package"} )
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
Edit 2 :
The architecture of the project is like :
- Parent project (my.package)
-Module Base (with IndexSetup class)
-Module Indexing (that depends on Base)
-Module Server (that also depends on Base)
The parent pom.xml reads like the following :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.package</groupId>
<artifactId>MyApp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--According to https://stackoverflow.com/questions/10665936/maven-how-to-build-multiple-independent-maven-projects-from-one-project-->
<modules>
<module>Base</module> <!-- Common resources which is a dependency in Indexer and Server -->
<module>Indexer</module> <!-- Indexing part with JavaFx-->
<module>Server</module> <!-- Server (spring boot) part of -->
</modules>
<name>MyApp</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<bootclasspath>${sun.boot.class.path}${path.separator}${java.home}/lib/jfxrt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<additionalClasspathElements>
<additionalClasspathElement>${java.home}/lib/jfxrt.jar</additionalClasspathElement>
</additionalClasspathElements>
</configuration>
</plugin>
</plugins>
</build>
Edit 3:
The problem originates from when the table to look at is specified:
Root<IndexSetup> from = criteriaQuery.from(IndexSetup.class);
Looking at hibernate sources not an entity is thrown whenever entityType == null. So I don't gather why the entity type is null here whereas it works outside of SpringBoot ?
Edit 4:
If I remove SpringApplication.run(ServerApplication.class, args); from the Server class' main method then the same call which was causing the issue ie :
LocalDatabase.getInstance(false) // no GUI
.getAllIndexSetups();
now works picobello. Of course it does not solve anything since I still need SpringBoot for the search! So for me it means that Spring Boot does not understand the hibernate configuration. I opened a new question to introduce the problem more accurately.
Any help appreciated,
I think you should add to your #EntityScan annotation package of your entities within second project/module
As first, some checking :
Is all your configuration only built with annotations in ServerApplication or any Java class, or are there any others external configurations in XML / YML files ? Maybe look for conflicts. We do prefer to not mix XML with annotation configuration, if possible.
Try to remove #Serializable (not really mandatory).
Try to move your entity in your root package (just as a test).
Check if the package which export #Entity is correct.
Question : what are you calling "module", it is a subpackage or Maven module or another thing ? Could we have the configuration of package names about this ?
Edit :
In the case of a multi-modules project, did you follow recommendations from spring.io about multi-modules projets ? Did you import the Spring BOM (or starter) in your submodules and did you test the Spring Boot Maven Plugin ?
Can you provide your application.properties (or application.yml whatever) with your datasource configuration ? You should check if your datasource (and JPA, driver class, ...) is correctly defined ; see spring.io
So it happened that I did not use correctly SpringBoot capabilities. Here are the steps I followed. Please remember the architecture of the project :
- Parent maven project (my.package)
|-Module Base (with IndexSetup class and [initialy] hibernate.cfg.xml in /resources. It also had in the beginning LocalDatabase class to access to the local db via hibernate)
|-Module Indexing (that depends on Base)
|-Module Server (that also depends on Base)
|-Database file (myLocalDB)
1) First I removed hibernate.cfg.xml from Base and dropped it into resources of the Indexing module. I did it because SpringBoot has its own configuration mechanism. I also removed LocalDatabase class from Base (since it would not be needed by SpringBoot) and dropped it too in the Indexing Module (where it is used indeed).
2) Following [this](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html] I added spring-boot-starter-data-jpa to the Server module pom.xml.
3) Following this tutorial I created a JPA Repository IndexSetupRepository with barely a single line of code :
public interface IndexSetupRepository extends CrudRepository<IndexSetup, Integer> {
}
4) In the Server application.properties I added those lines :
# Embedded database configuration
# The embedded database file is one level above the Server folder (ie directly within the parent project)
# we use the auto server mode to be able to use the database simultaneously in the indexer and the server
spring.datasource.url=jdbc:h2:file:../myLocalDB;AUTO_SERVER=TRUE
spring.datasource.username=myName
# This parameter helped me discover that SpringBoot was not targetting the right table name.
spring.jpa.hibernate.ddl-auto=validate
5) As SpringBoot was telling me it could not find table named index_setup (see camel case converted to _), I had to add this line to the application.properties :
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
6) Now as I got "Entity not managed", I eventually added #EntityScan annotation to the Server main class as many of you advised me to do.
#EntityScan("my.package.Entities")
Please note that #EntityScan should point to the folder containing the entity class not the entity class itself ie #EntityScan("my.package.Entities.IndexSetup") did not work.

Setting SPRING_PROFILES_ACTIVE inside of Spring Boot custom embedded launch.script

We have executable spring boot jars. Some environment variables are provided via the runtime account's .bashrc , including SPRING_PROFILES_ACTIVE . This is set at runtime through checking some system parameters.
In order to enable a truly portable application, we would like to set these variables inside a custom version of the Spring Boot executable launch script (launch.script) instead of relying upon a custom .bashrc being deployed somewhere.
i.e. the launch script runs the custom shell code that is currently in our bashrc .
We could then throw the Spring Boot executable jar on one of our boxes without having to deploy the custom .bashrc .
We have copied the default Spring Boot launch.script and prepended setting our environment variables. We replace the default script with our custom one by using the spring-boot-maven-plugin. Using echo statements, we know that the new launch.script replaces the default one.
One environment variable we are setting dynamically is SPRING_PROFILES_ACTIVE . Through an echo statement, I know that the variable is being set correctly inside of our custom launch.script. However, that value is not being propagated to the application. i.e. the spring profile at application startup is always 'default', versus L0, L1 or whatever we're trying to set.
I have exported the variable using export and declare -x .
Is what we are doing at all feasible, or is setting SPRING_PROFILES_ACTIVE in the launch.script too late ?
In the snapshot version(2.0.0.M7) there is a new property substitution named inlinedConfScript, we can use this feature to set some environment variables before application startup.
The <build> setting in pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<embeddedLaunchScriptProperties>
<inlinedConfScript>${project.basedir}/my.script</inlinedConfScript>
</embeddedLaunchScriptProperties>
</configuration>
</plugin>
</plugins>
</build>
Create my.script in the the same directory of the project's pom.xml
export SPRING_PROFILES_ACTIVE=production

Error: No class Def found error while setting up Java as a Windows Service

Following is the error log I'm getting:
I'm using
wrapper-windows-x86-32-3.5.25-pro
in order to make my already developed application in Spring-boot. I wanted to execute this application as a windows service but I'm not.
This problem is specific to Tanukisoftware as I'm unable to configure it.
PFB the configuration I'm using for setting up the class path here:
wrapper.java.classpath.1=../lib/wrappertest.jar
wrapper.java.classpath.2=../lib/wrapper.jar
wrapper.java.classpath.3=../lib/slf4j-api-1.7.5
wrapper.java.classpath.4=../lib/myApp.jar
even if myApp.jar contains the slf4j classpath already and its running already. I think this is library specific problem and its not finding up the classpath even if I explicitly set it like did above.
Can you please let me know how it can be solved?
Did you try building a fat jar of your application ? You can add following lines to your Spring Boot project's pom.xml to repackage jar file:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Besides, your following property line seems invalid:
wrapper.java.classpath.3=../lib/slf4j-api-1.7.5
Is it pointing a jar file actually ?
slf4j-api-1.7.5 should have a .jar extension. That is possibly confusing things.
Also, even just as a debugging step, try running your Windows service using Apache ProcRun to see if your results are any different.

Categories