Springboot JPA with Tomcat 7 - spring-boot

I have been trying to deploy springboot with JPA on Tomcat 7. The app works fine when running with java -jar. But with deployed on Tomcat, it is often saying can't find the bean with extended JpaRepository interface.
What is the proper way to deploy springboot on Tomcat 7?
Thanks in advance.

some times this will helps
in Application.java
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class Application extends SpringBootServletInitializer
Add this Dependency and Plugin to pom.xml
<!--For Build War File-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
This works for me
Hope this will helps...!

Related

How should I perform integration testing on a SpringBoot library, that isn't an application

First up, a disclaimer, I'm not entirely happy with the architecture of what I'm about to ask about!
We have a Spring based project that produces a library as a jar. That library includes all the usual controller/service/jpa (repositories) layers you might expect but no boot application to start it all up.
The idea being various projects within our organisation can import the jar and get instant addition of a common (HTTP) API.
Unit tests work ok.
*IT.java tests are another matter.
Run in isolation by the IDE from the test/java/ hierarchy they run ok and pass.
However when running via maven as part of the build they fail.
[ERROR] ControllerIT » IllegalState Unable to find a #SpringBootConfiguration...
We have a Boot configuration in the test hierarchy which the ITs must be using when run via the IDE, but when running the maven build it seems it can't be found to start up the application (understandably as it is in the test package tree).
The boot file we do have is intended to be no more than a test harness to run the lib, to run the ITs.
We have h2 in the Maven test scope, but it isn't wanted in the final library (that is up to the host application to provide a datasource/connection etc).
Requirement:
Start up the API library in an application for testing
Run the tests as part of Maven build
H2 should not end up in final jar
Symptoms when running mvn install
[ERROR] ControllerIT » IllegalState Unable to find a #SpringBootConfiguration...
Presumably need some config somewhere in pom? Already using package.Boot in the Springboot maven plugin config.
Maybe just need to figure out the magic config to point it at the src/test/... Boot.class rather than src/main/...Boot.class
Question(s):
Does spring have a 'correct' way to achieve what we want (I'd go with MicroServices, but not an option because ... reasons)?
How should we go about implementing ITs against a H2 driven SpringBoot application when we don't want to include the bootable class (or H2 lib) in product jar?
Should we be creating a separate Maven module just for the ITs (with a dependency on the library module)?
Abbreviated Maven pom:
<properties>
<version.spring-boot>2.1.13.RELEASE</version.spring-boot>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${version.spring-boot}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.28.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.28.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.4.0</version>
<type>pom</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<!-- other dependencies excluded for brevity -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${version.spring-boot}</version>
<configuration>
<!-- file lives in test hierarchy -->
<mainClass>org.my.packages.test.Boot</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<skip>true</skip><!-- Skipping unit tests while trying to sort ITs -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<failIfNoTests>true</failIfNoTests>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</execution>
</plugin>
</plugins>
</build>
The Spring Boot config:
#SpringBootApplication()
public class Boot extends SpringBootServletInitializer
{
public static void main(String[] args)
{
SpringApplication.run(Boot.class, args);
}
}
IT configuration:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ControllerIT
{
#Autowired
private TestRestTemplate restTemplate;
...
}
Number 2 lead me to looking into params of #SpringBootTest.
I ended up with ...
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = ITConfig.class)
Where ITConfig is:
#SpringBootApplication()
public class ITConfig extends SpringBootServletInitializer
{
public static void main(String[] args)
{
SpringApplication.run(org.lhasalimited.libraries.ITConfig.class, args);
}
}
That appears to be working. Thanks for the hint.
Let me propose one way of solving this issue, there are might be others:
#SpringBootTest annotation is intended to mimic the startup of the full fledged spring boot application.
It scans the packages up to the point where it finds #SpringBootConfiguration annotataion (this annotation is placed on #SpringBootApplication already) and this way it understands that the packages down to the package in which the main class is found should be scanned (to find all the beans).
Besides that, it does many other things that spring boot application does during the start: loading configurations (application.properties/yaml) obeying the conventions of spring boot application, loading auto-configurations (stuff inside spring.factories) and so forth.
Bottom line you'll have a full-fledged spring boot application (usually microservice) loaded inside the test.
So far so good, but you say that you don't really have a spring boot application. So I see three ways:
Introduce an artificial class with #SpringBootConfiguration in the src/test/java/whatever-package-close-to-root folder (note, its in 'test', not in src/main)
Use #SpringBootTest with a parameter of "Configuration". This will mean that SpringBootTest won't use all this scanning up-and-then-down process and instead you'll instruct it to use the concrete context configuration.
Do not use #SpringBootTest annotation at all, and prefer a "usual" #ContextConfiguration - yes, you won't have the power of spring boot but as I've said above you probably won't need it. In addition these tests will be way faster, especially if you'll provide many "#Configuration" classes and will load only "relevant" parts of the library during the tests.
For example, if you test the DAO, there is no point in loading web related stuff.

Adding Spring (Boot?) to existing RESTEasy JAX-RS application

I have an existing Maven project based on JAX-RS using RESTEasy. It works great! It creates a WAR that I deploy to Tomcat running on Ubuntu. It's clean and follows the latest standards. The POM is simple:
...
<packaging>war</packaging>
...
<dependencies>
...
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>3.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.1.0.Final</version>
</dependency>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
...
I don't need any web.xml because I'm using the latest Java EE annotations:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/")
public class MyRESTApplication extends Application {
final FooResource fooResource = new FooResourceService();
...
#Override
public Set<Object> getSingletons() {
return ImmutableSet.of(fooResource);
}
}
This is all simple and it's working so great! Now I just want a way to easily change FooResource implementations based on the profile --- in other words, wire my singletons. That's where Spring comes in, right? And I've been told that Spring Boot makes Spring even more awesome, and you can use it with anything, and it gives you an actuator that allows you to gain real-time inside on the health of your system.
Unfortunately all the Spring Boot books and tutorials seem to think I'm starting with one of their quick-start applications. But I already have a great, simple application. I just want to:
Get my application wiring, based on profiles, from an external configuration file (not annotations) via Spring.
Get whatever other goodness comes from Spring Boot, because apparently it is awesome and will completely transform my application.
How do I add Spring (or Spring Boot) to this simple little JAX-RS application?
we solved it that way, that we created a singleton spring bean, let's call it ServiceStartupClass, where we register all JAX-RS services.
Here some code snippet how we start our services:
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
#Component
#ApplicationPath("/")
public class ServiceStartupClass extends ResourceConfig {
#PostConstruct
public void startup() {
register(FooResource.class);
...
}
}
If you need any further help, let me know

Import spring boot app into another project

So I am attempting to add a spring boot executable jar as a dependency in another project (Testing framework).
However once added to the pom and imported. Java imports don't work properly. If I look inside the jar all packages are prepended with:
BOOT-INF/classes.some.package.classname.class
There is also some spring boot related packages, MANIFEST etc etc.
Not if I switch the spring boot app's build to just install and deploy a regular jar using the spring-boot-maven-plugin
This changes and everything works fine. Unfortunately this is not a solution for us as we lean on the executable jar as part of our release process.
Can I build a deploy both versions of the jar and use a classifier to determine each?
Thanks
Turns out this exact scenario can be achieved using the spring-boot-maven-plugin.
Spring boot app's pom:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.1.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
...
</plugin>
project using the spring boot jar can be added as normal:
<dependency>
<groupId>com.springboot</groupId>
<artifactId>app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
OR if you want to reference the executible jar
<dependency>
<groupId>com.springboot</groupId>
<artifactId>app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>test</scope>
<classifier>exec</classifier>
</dependency>

Cannot start an OSGI bundle that embed spring boot in liferay 7

I want to develop a standalone bundle that implement a service using spring boot and spring data jpa (without web).
The bundle aims to create a spring context to facilitate the creation of Repository, and in teh bundle activator, I create the spring boot application, get an implementation of service that use the injected repository and this service will be registered as an OSGI service.
The bundle will be deployed on Liferay 7 so there is no ready bundles to help exporting packages (for jpa ...), to make simpler the idea is to have a standalone bundle that embed all dependencies in the bundle classpath (no package to import from outside the bundle)
Is there any sample that can help ? and is that a good idea ?
The problem was, when trying to start the bundle, it fails with "Caused by: java.lang.ClassNotFoundException: org.osgi.framework.BundleActivator .."
The following classes are simplified sampel to demonstates the problem (normally it must be a separate bundle that define and export the api that will be implemented by the bundle in question, but in this sample this is a unique bundle with 4 classes)
1/ The bundle activator class
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.springframework.context.ApplicationContext;
public class Activator implements BundleActivator
{
#Override
public void start(BundleContext context) throws Exception
{
ApplicationContext springCtx = SpringFramework.getContext();
UserDao dao = springCtx.getBean(UserDao.class);
userDaoReg = bc.registerService(UserDao.class.getName(), dao, new Hashtable());
}
#Override
public void stop(BundleContext context) throws Exception
{
/** **/
}
}
2/ class to launch the spring boot application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class SpringFramework {
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(SpringFramework.class);
}
public static ConfigurableApplicationContext getContext()
{
if (context == null) {
context = SpringApplication.run(SpringFramework.class);
}
return context;
}
}
3/ The UserDao to be registered as a service
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserDao extends JpaRepository<User, Integer>
{
}
4/ and a simple JPA Entity class "User"
And these are dependencies and plugin used in the pom.xml
<dependencies>
<!--OSGI dependencies-->
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.0.RELEASE</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Import-Package>!*</Import-Package>
<Bundle-Activator>hello.Activator</Bundle-Activator>
<Embed-Dependency>*</Embed-Dependency>
<!--<Embed-Transitive>true</Embed-Transitive>-->
</instructions>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This is the generated manifest in the jar
Manifest-Version: 1.0
Bundle-SymbolicName: test-spring-boot-no-web
Archiver-Version: Plexus Archiver
Built-By: XXX
Bnd-LastModified: 1475774161783
Bundle-ManifestVersion: 2
Embed-Dependency: *
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Spring-Boot-Version: 1.3.0.RELEASE
Tool: Bnd-3.2.0.201605172007
Main-Class: org.springframework.boot.loader.JarLauncher
Embedded-Artifacts: org.osgi.core-6.0.0.jar;g="org.osgi";a="org.osgi.c
ore";v="6.0.0",slf4j-api-1.7.13.jar;g="org.slf4j";a="slf4j-api";v="1.
7.13",spring-boot-starter-1.3.0.RELEASE.jar;g="org.springframework.bo
ot";a="spring-boot-starter";v="1.3.0.RELEASE",spring-boot-starter-dat
a-jpa-1.3.0.RELEASE.jar;g="org.springframework.boot";a="spring-boot-s
tarter-data-jpa";v="1.3.0.RELEASE",persistence-api-1.0.2.jar;g="javax
.persistence";a="persistence-api";v="1.0.2",javax.transaction-api-1.2
.jar;g="javax.transaction";a="javax.transaction-api";v="1.2"
Export-Package: hello;version="1.0.0"
Bundle-Name: spring-boot-no-web
Bundle-Version: 1.0.0.SNAPSHOT
Bundle-ClassPath: .,org.osgi.core-6.0.0.jar,slf4j-api-1.7.13.jar,sprin
g-boot-starter-1.3.0.RELEASE.jar,spring-boot-starter-data-jpa-1.3.0.R
ELEASE.jar,persistence-api-1.0.2.jar,javax.transaction-api-1.2.jar
Bundle-Activator: hello.Activator
Start-Class: hello.SpringFramework
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_101
I saw 2 questions in your post so I'll try to answer those:
Is there any sample that can help ?
I don't think so! What you are trying to do seems weird to me. See below for details.
... is that a good idea ?
You are saying you want "standalone bundle" that "will be deployed on Liferay 7"! It may be you just picked the wrong words but the way you state it, you are trying to have mutually exclusive things.
There is no such thing as "standalone bundle". I assume you mean standalone java application (executable Jar file that has the OSGi framework embedded). You can build such applications in a number of different ways. For example there is excellent tutorial how to do this from EnRoute. You can not however deploy such executable jar as it typically is not a OSGi bundle. While technically you can make it a bundle, you may run into all kinds of issues due to the embeded runtime and dependencies.
In Liferay 7 (and any outher product that has OSGi container) you can run a bundle in the runtime environment the product defines. The bundle must be resolvable at runtime. It may have all it's dependencies embedded but that defeats the purpose of modularity unless it provides something to outher bundles (which does not seem to be your case).
From that perspective what you are trying to do seems to be a bad idea. Moreover Spring Boot is a framework to build stand alone java applications and as such have it's own assumptions. Making it work inside an OSGi container is likely not a trivial task (if at all possible)
Perhaps better idea would be to have some bundles providing the business logic only. Then you could deploy those bundles in Liferay and laverage Liferay's capabilities to serve REST servces. You could use the exact same bundles to cunstruct standalone application that uses Spring or CXF or something else.
Notes about your code
your main class is org.springframework.boot.loader.JarLauncher. If you run this jar it will start Spring which likely will be totally unaware of OSGI runtime.
you have org.osgi.core-6.0.0.jar is your bundle's classpath with is basically the OSGi's runtime. This will cause issues if deployed into a OSGi runtime and my be the reason why you see
Caused by: java.lang.ClassNotFoundException: org.osgi.framework.BundleActivator ..

Spring 4 Java Config Transactions Proxy and Aspecj

I am creating a new project that uses aspectj transactions. It also uses legacy jars that contain services that are using the proxy method where an interface is required.
I am using java config and when I set
#EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
Then I get the following exception thrown with accessing the proxy style services from the legacy libs:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
If I change to:
#EnableTransactionManagement(mode=AdviceMode.PROXY)
Then I don't get the problem but I can't then use the aspectj style transactions in my new project.
I've tried adding two #EnableTransactionManagement annotations with each adviceMode, but that is not allowed.
Here is the annotated class
#EnableWebMvc
#Configuration
#ComponentScan("com.mydomain")
#EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
public class ApplicationConfig extends WebMvcConfigurerAdapter {
...
I've also added the aspectj maven plugin to the legacy project in the hope that it would handle the weaving at compile time and thus aspectj transactions would work. But this has not solved the problem.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
Is it possible to have spring deal with both advice modes? How would I do this?
Or is there another way around this problem.
The problem was with the aspectj config on the legacy project.
When I ran mvn compile it became apparent. I had to add the dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
That got it working when compiled using maven, but I it would still not work in eclipse. I had to right click on the legacy project in eclipse:
Configure>Convert to Aspectj Project
Then I could deploy from eclipse and I had aspectj transactional support in the legacy jars.

Resources