Two Spring Boot projects both with #SpringBootApplication - spring

I have a data project and UI project. Both projects are Spring Boot applications. Both projects have the same root package (com.myorg) with a main class annotated with #SpringBootApplication.
Data project's main class is:
package com.myorg;
#SpringBootApplication
public class DataApplication {
public static void main(String[] args) {
SpringApplication.run(DataApplication.class, args);
}
}
The UI project's main class is:
package com.myorg;
#SpringBootApplication
public class UiApplication {
public static void main(String[] args) {
SpringApplication.run(UiApplication .class, args);
}
}
The UI project depends on the data project via the following Gradle dependency:
dependencies {
compile('com.myorg:data:1.0')
}
If I run the UI application, it runs without issue. However, if I run an integration test within the UI application such as follows:
package com.myorg
#RunWith(SpringRunner.class)
#SpringBootTest
public class UiIntTest {
#Test
public void contextLoads() {
}
}
The following initialization error occurs:
java.lang.IllegalStateException: Found multiple #SpringBootConfiguration annotated classes
In the data project's main class, if I replace #SpringBootApplication with
#Configuration
#EnableAutoConfiguration
#ComponentScan({ "com.myorg" })
I get the following initialization error when trying to run its integration tests:
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
For example, if I try to run:
package com.myorg
#RunWith(SpringRunner.class)
#SpringBootTest
public class DataIntTest {
#Test
public void contextLoads() {
}
}
How can I properly configure the data and UI projects?

You need to specify which Spring Boot Main class to use along with #SpringBootTest:
#SpringBootTest(classes = YourUiSpringBootApp.class)

You shouldn't have two SpringApplication annotations in the same package.
Package one.
twoapps.one;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackageClasses = {One.class})
#EnableAutoConfiguration
public class One extends SpringApplication {
}
Package two.
twoapps.two;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackageClasses = {Two.class})
#EnableAutoConfiguration
public class Two extends SpringApplication {
}
Root package and launcher
package twoapps;
import org.springframework.boot.SpringApplication;
import twoapps.one.One;
import twoapps.two.Two;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Application {
public static void main(String[] args) throws Exception {
new Thread(() -> SpringApplication.run(One.class, args(args, "--spring.profiles.active=one"))).start();
new Thread(() -> SpringApplication.run(Two.class, args(args, "--spring.profiles.active=two"))).start();
}
private static String[] args(String[] args, String s) {
List<String> collect = Arrays.stream(args).collect(Collectors.toList());
collect.add(s);
String[] strings = collect.toArray(new String[]{});
return strings;
}
}
This is a terrible idea. please don't do it. It is much better to have two different projects and a common project.

Related

How do I annotate my JUnit test so it will run the way my Spring Boot app runs?

I have a Spring Boot web application that I launch by running this class ...
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The web app has a JSP/HTML front end served up by Spring MVC Controllers which talk to Services which talk to DAOs which uses Hibernate to read/write Entities to a MySQL database.
All the components and services get instantiated and #Autowired and the web app runs fine.
Now, I want to build JUnit tests and test some of the functionality in the Services or the DAOs.
I started writing a JUnit test like below, but I quickly got stuck on not knowing how to instantiate all the #Autowired components and classes.
public class MySQLTests {
#Test
public void test000() {
assertEquals("Here is a test for addition", 10, (7+3));
}
#Autowired
UserService userService = null;
#Test
public void test001() {
userService.doSomething("abc123");
// ...
}
}
I basically want the web application to start up and run, and then have the JUnit tests run the methods in those Services.
I need some help getting started ... is there some kind of JUnit equivalent of the #SpringBootApplication annotation that I can use in my JUnit class?
Answering my own question ... I got it working like this ...
Annotated the test class with:
#RunWith(SpringRunner.class)
#SpringBootTest
The test class had to be in a package above the #Controller class ... so my test class is in com.projectname.* and the controller is is com.projectname.controller.*
The working code looks like this ...
package com.projectname;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.projectname.controller.WebController;
#RunWith(SpringRunner.class)
#SpringBootTest
public class Test1 {
#Autowired
private WebController controller;
#Test
public void contextLoads() throws Exception {
assertNotNull("WebController should not be null", controller);
}
}

Spring boot: #Repository class not found to inject

This is my Spring boot application related code:
#ComponentScan({"net.gencat.transversal.espaidoc.scheduler", "net.gencat.transversal.espaidoc.backoffice"})
public class SchedulerApplication {//...}
By other hand, I've a repository on package net.gencat.transversal.espaidoc.backoffice.dao:
#Repository
public interface DocumentDAO extends CrudRepository<Document, String> {
}
So, I've a service with a DocumentDAO dependency:
#Service
public class DocumentServiceBackOffice {
private DocumentDAO documentDAO;
public DocumentServiceBackOffice(DocumentDAO documentDAO) {
this.documentDAO = documentDAO;
}
}
However, I'm getting this message:
NoSuchBeanDefinitionException: No qualifying bean of type 'net.gencat.transversal.espaidoc.backoffice.dao.DocumentDAO' available
I've also tried adding #EnableJpaRepositories, but it still doesn't work.
Any ideas?
EDIT
This is my SpringApplication class:
package net.gencat.transversal.espaidoc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;
import net.gencat.transversal.espaidoc.common.config.FrontOfficeProperties;
import net.gencat.transversal.espaidoc.common.config.RedisConfiguration;
#SpringBootApplication(exclude = JmxAutoConfiguration.class)
#EnableConfigurationProperties({
FrontOfficeProperties.class
})
#Import(RedisConfiguration.class)
#EnableScheduling
// #ComponentScan("net.gencat.transversal.espaidoc")
//#EnableJpaRepositories
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
EDIT2:
I've just realized on spring logs that there's some issue related with DocumentDAO:
--- [ main] .RepositoryConfigurationExtensionSupport : Spring Data JPA - Could not safely identify store assignment for repository candidate interface net.gencat.transversal.espaidoc.backoffice.dao.DocumentDAO.
Try adding the following:
#EnableJpaRepositories(basePackages="net.gencat.transversal.espaidoc.backoffice.dao")
public class SchedulerApplication

How to make Spring IoC container available through out project

I feel stupid to even ask for this but I spent days looking for the answer and I'm still with nothing.
I wanna include simple Spring IoC container in my project. All I want it to do is to allow me Injecting/Autowiring some reusable objects in other classes. What I've done so far looks like this:
-> Project structure here <-
Configuration code:
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.util.Random;
#Configuration
#ComponentScan(basePackages = "com.example")
public class AppConfig {
#Bean
public Random rand() {
return new Random(42);
}
#Bean
public String string() {
return "Hello World!";
}
}
Main class code:
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Random;
public class Main {
#Autowired
Random rand;
#Autowired
String string;
public static void main(String[] args) {
// workflow
Main main = new Main();
System.out.println(main.string);
}
}
AnotherClass code:
package com.example.deeperpackage;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Random;
public class AnotherClass {
#Autowired
Random rand;
#Autowired
String string;
public void methodToBeCalled() {
// TODO
System.out.println(string);
}
}
How can I make these #Autowired annotations work? Do I have to instantiate container in every single class in which I want to autowire components? I've seen in work a oracle app which used Spring and #Inject to distribute objects to numerous classes and there was no container logic in any class available for me. Just fields with #Inject annotation. How to achieve that?
Simply add the annotation #Component on the classes you want to inject :
#Component
public class AnotherClass {
...
}
But you cannot inject static attributes and when you do new Main(), no Spring context is being created. If you use Spring Boot, you should look at how to write a main with it.
https://spring.io/guides/gs/spring-boot/

#SpringBootTest cannot find main class method for Testing:

I have the following test class and it cannot find the main class for spring-boot. I am using gradle and had this working fine when I was using maven so I have a suspicion it has something to do with Gradle.
I have made the project more modular so they're several boot projects. Example"
service-module and domain-module. I am currently testing my service module
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = ServiceApplication.class )
#TestPropertySource(locations = "classpath:application.properties")
#Transactional
public class ApplicantImplTest {
However it is unable to resolve ServiceApplicantion.com
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
ServiceApplication is located under src->main->java
In my gradle I have:
description = ''
dependencies {
compile project(':util')
compile project(':domain')
}

how to use the ApplicationArguments in spring-boot

I am learning the Spring-Boot(I am new to it), reading the Spring Boot Document. In the 23.6 Accessing application arguments, It talk about the ApplicationArguments, and the code is:
package com.example.project;
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import java.util.*;
#Component
public class MyBean {
#Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
System.out.println(debug);
System.out.println(files);
}
}
It says if run with "--debug logfile.txt" debug=true, files=["logfile.txt"].
But in my project, I don't know how to run it. I create the spring-boot using Maven: The Project Structure
In Spring Boot doc ApplicationArguments is autowired in a bean. Here is a more hands on example where it's used in a Main method.
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args).stop();
}
#Override
public void run(ApplicationArguments args) throws Exception {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
System.out.println(debug);
System.out.println(files);
}
}
Assuming that you have an Application class with annotation #SpringBootApplication like in the answer provided by a.b.d.
To be able to provide the arguments within IntelliJ IDEA environment you will need to first Run the main method and then Edit 'Run/Debug Configurations' and under Main Class fill Program arguments field with "--debug logfile.txt":
In one word like a thousand :
the 'Program arguments' in your IDE field prefixed by -- is simply the same name as the 'Option' expected in the 'ApplicationArguments'.
Hence you can match --debug and "args.containsOption("debug")".

Resources