Sonar complains about Spring Boot configuration - spring

I have this class to start up the spring-cloud config server. It is a spring-boot application.
#SpringBootApplication
#EnableConfigServer
#EnableDiscoveryClient
public class ConfigServerApplication {
public static void main( String[] args ) {
SpringApplication.run( ConfigServerApplication.class, args );
}
}
The application runs fine and all my unit tests are fine. However, in our bamboo pipeline, it will initial a sonar process to analyze the code. We keep getting these minor warnings indicating the following:
Utility classes should not have a public constructor
I know that this is a minor issue, but I have been tasked with removing these from our code.
Ideally, you would mark the class final and provide a private constructor, or so all searches provide as a solution. However, a Spring Configuration class cannot be made final and cannot have a private constructor.
Any ideas how to resolve this?

I'm afraid this isn't a problem spring-boot or spring-cloud can solve. You need to add exceptions to your sonar configuration.

Adjusting your sonar settings would be a nicer approach of course, but if you want to please the machine spirits, you can simply add a non-static dummy function to your class, making it "non-utility" in the eyes of the Sonar checker.

It's easy to test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class YourApplicationTest {
#Test
public void shouldLoadApplicationContext() {
}
#Test
public void applicationTest() {
YourApplication.main(new String[] {});
}
}
Now Sonar is saying, this is tested!
(Kudos goes out to: Robert # https://stackoverflow.com/a/41775613/863403)

Related

IntelliJ cannot autowire the parameter in #ServiceActivator method if I use #EnableAutoConfiguration

With auto configuration enabled, my Spring Integration service activator gives me an error in IntelliJ: "Could not autowire. No beans of 'String' type found."
If I disable auto configuration, the error goes away.
Can I exclude a class from auto configuration to "fix" this? How do I know which?
Here's the #ServiceActivator:
#Slf4j
#MessageEndpoint
public class StringProcessor {
#ServiceActivator(inputChannel = "channel1")
public void processString(String s) {
log.info(s);
}
}
IntelliJ error message
The error can be toggled by the #EnableAutoConfiguration (#SpringBootApplication) annotation:
//#SpringBootApplication
#ComponentScan
#Configuration
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
How do I figure out if this is an IntelliJ false alarm, a Spring Integration issue, or am I holding it wrong? ;o)
That's IntelliJ IDEA false alarm and wrong assumption at the same time.
The signature and structure of that #ServiceActivator was never designed for injections.
Such a method is called at runtime when a message is appeared in that channel1. So, an endpoint activate that service method and passes a payload of message into an s argument of the method. With respective converting if necessary. The atuwiring assumption over there is a bug in the IDE.
See more about service activator in the docs: https://docs.spring.io/spring-integration/reference/html/messaging-endpoints.html#service-activator
It is a false alarm, and somebody has raised this as an issue with JetBrains
https://youtrack.jetbrains.com/issue/IDEA-264916
Would you mind clicking the thumbs up next to the title so Jetbrains knows that other people would like this issue fixed.
In the meantime you can disable the introspection at the method level with the following
#Slf4j
#MessageEndpoint
public class StringProcessor {
#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
#ServiceActivator(inputChannel = "channel1")
public void processString(String s) {
log.info(s);
}
}
This type of warning is always a 'best guess' from IDEA, and as configs get more complicated, particular if you are refering to beans created in external jars it will happen more often.
They do not stop compilation or initial execution, but Spring itself will terminate execution if the warning is actually correct.

how to conditionally not create beans in spring boot?

In my application, I have a component that reads data from other system when the application is started.
However, during testing, I don't want this component to be created
#Component
#Slf4j
public class DeviceStatisticsSyncHandler {
#EventListener
public void handle(ApplicationReadyEvent event) {
syncDeviceStatisticsDataSync();
}
#Value("${test.mode:false}")
public boolean serviceEnabled;
}
I can use condition to solve this, but other code readers need to understand, so I don't think this is a very good method:
#EventListener(condition = "#deviceStatisticsSyncHandler .isServiceEnabled()")
public void handle(ApplicationReadyEvent event) {
syncDeviceStatisticsDataSync();
}
public boolean isServiceEnabled() {
return !serviceEnabled;
}
#Value("${test.mode:false}")
public boolean serviceEnabled;
My application doesn't use Profiles, is there any other method to solve this problem.
Spring Boot version:2.1.3
One possible option is not to load the DeviceStaticsticsSyncHandler at all if you're in a test mode.
The "test.mode" is not a good name here, because the production code contains something tightly bound to the tests.
How about the following approach:
#Component
#ConditionalOnProperty(name ="device.stats.handler.enabled", havingValue = "true", matchIfMissing=true)
public class DeviceStatisticsSyncHandler {
// do whatever you need here, but there is no need for "test.mode" enabled related code here
}
Now in Tests you can define a test property "device.stats.handler.enabled=false" on the test itself or even place that definition in src/test/reources/application.properties so it will be false for all tests in the module.
An obvious advantage is that this definition is pretty much self explanatory and can be easy understood by other project maintainers.
for me, it's not the case of the condition rather environment-related. I will solve this problem using spring profile.
Step 1: Create an Interface first
public interface DeviceStatisticsSyncHandler {
public void handle(ApplicationReadyEvent event);
}
Step 2: Create an Implementation for production
#Component
#Profile("!test")
public class DeviceStatisticsSyncHandlerImpl implements DeviceStatisticsSyncHandler {
#EventListener
#Override
public void handle(ApplicationReadyEvent event) {
syncDeviceStatisticsDataSync();
}
}
step 3: create an implementation of test
#Component
#Profile("test")
public class DeviceStatisticsSyncHandlerTestImpl implements DeviceStatisticsSyncHandler {
#EventListener
#Override
public void handle(ApplicationReadyEvent event) {
//do Nothing
}
}
final step
All you need to do is set/toggle the property
-Dspring.profiles.active=test
or
-Dspring.profiles.active=prod
I found a way to achieve this without any further external configuration required.
The idea is to create a general configuration that applies to all integration tests and use #MockBean there to replace the real bean. So one should create a class like this under the test classpath (i.e. that is not scanned during normal application launch):
#Configuration
public class IntegrationTestConfiguration
{
#MockBean
public DeviceStatisticsSyncHandler deviceStatisticsSyncHandler;
}
I was actually surprised that #MockBean can be used here, but the Javadoc explicitly points that out: Can be used as a class level annotation or on fields in either #Configuration classes, or test classes that are #RunWith the SpringRunner..

#Value for custom values is not showing up

I have a project in Spring Boot (1.5.9). I have properties in an application.properties in src/main/resources and in an external application.properties. I also can provide values through the command line.
My main class looks like this:
#SpringBootApplication
#SpringBootConfiguration
#EnableJpaRepositories
#EnableEncryptableProperties
#Import(RepositoryRestMvcAutoConfiguration.class)
public class Application {
public Application() { super(); }
public static void main(String[] args) {
final SpringApplication app = new SpringApplication(Application.class);
app.run(args);
}
}
I have a different class that looks something like this:
#Component
public class MyAuthenticationProvider extends AuthenticationProviderInterface {
#Value("${myproject.authentication.url:https://blah:8443}")
private String authenticationURL = "https://test.blah:8443";
#Override
public void afterPropertiesSet() {
System.err.println(authenticationURL);
}
..... other stuff.....
}
From the System.err, I get https://test.blah:8443.
Now, I can get all of my major variables: spring.main.banner-mode, spring.datasource.name, etc. I just do not seem to be able to get my custom variables--myproject.authentication.url or myproject.authentication.accessstring.
The spring variables are behaving as expected--I can follow precedence from the properties files to the command line. It's only the custom variables that are giving me fits.
Does anyone have any suggestions? I'm trying to give good information, but I am typing between two unconnected computers and I will occasionally have a typo.
Thank you.
Change #Comopnent to #Component.
OK. This was blatant stupidity and Eclipse "helping" me again. The Save actions added a "final" and (unsurprisingly) the values were not being updated. Sorry for wasting people's time.

JUnit testing got initializationError with java.lang.Exception: No tests found matching

When running JUnit testing , it gave an initializationError: No tests found matching. Like this:
prodapi-main-junit
initializationError(org.junit.runner.manipulation.Filter)
java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=testCreateSite], {ExactMatcher:fDisplayName=testCreateSite(com.company.product.api.web.rest.HostControllerTest)], {LeadingIdentifierMatcher:fClassName=com.company.product.api.web.rest.HostControllerTest,fLeadingIdentifier=testCreateSite]] from org.junit.internal.requests.ClassRequest#3c0f93f1
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:40)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:77)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:68)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:43)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:444)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
While the testing code is as below:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = ProductApplication.class)
#WebAppConfiguration
public class HostControllerTest{
#Test
public void testCreateSite() throws Exception {
......
}
}
It should be fine to load the class, running well. There're other modules similar with this one, they're fine to run.
I have checked the possible causes:
someone said that missing "Test" annotation result in this error.
While the code did have the annotation as you can see.
some said the build path should be configured to do the build under the testing source folder, getting the testing class, and export.
And that configuration I double-checked worked as well.
maybe testing classes are not generated in the compile time, while I can see those testing classes under the destination folder.
I don't know whether there're any other possible things can get Junit testing error like this. Maybe I should check the class loader?
After googled some answers. I found there's an issue talked about this case as below:
https://github.com/junit-team/junit4/issues/1277 (FilterRequest may hide the real failure cause(exception) of a test)
Here're the steps I tried:
1. don't select the testing function alone, while select "Run all the tests in the selected project" option on the Test Tab, when select the Junit project name
after click on Run->"Run(Debug) Configuration"
2. You can get the details of the error as follows:
initializationError(com.company.product.api.web.rest.HostControllerTest)
java.lang.Exception: Method testSetDBConfiguration should have no parameters
at org.junit.runners.model.FrameworkMethod.validatePublicVoidNoArg(FrameworkMethod.java:76)
at org.junit.runners.ParentRunner.validatePublicVoidNoArgMethods(ParentRunner.java:155)
3.according to the details given by eclipse above, I removed the argument of that function, the initializedError just disappeared.
So this issue rises due to the new added testing function has unnecessary input argument.
The incorrect code :
#Test
public void testSetDBConfiguration(String name) throws Exception {
Changed to
#Test
public void testSetDBConfiguration() throws Exception {
Had the same issue with PowerMock #RunWith(PowerMockRunner.class) then discovered that my #Test was the wrong implementation. Was using
import org.junit.jupiter.api.Test;
I switched to import org.junit.Test; and that fixed the problem for me.
I have found the below solution which worked for me.
your Application #SpringBootApplication package name
and Test package name should be same .
see if it helps.
Happy coding.
First able Make sure that your methods annotated #test as well as the test class are public.
I had a similar error when my test method was private. It needs to be public.
I had the similar problem and later realized that my main spring boot application configuration was not scanning through the packages that had my test classes in
Main class was scanning packages - {"com.mycmp.prj.pkg1", "com.mycmp.prj.pkg2", "com.mycmp.dependentprj.pkg5"}
Test class was in package - com.mycmp.prj.pkg3
Problem got fixed by fixing our base packages to scan all packages from current project and only scan limited needed packages from dependent libraries
Main java class
#SpringBootApplication(scanBasePackages = {"com.mycmp.prj.pkg1", "com.mycmp.prj.pkg2", "com.mycmp.dependentprj.pkg5"})
public class MyApplication extends SpringBootServletInitializer {
public static void main(final String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
#Bean
public FilterRegistrationBean<Filter> customFilters() {
final FilterRegistrationBean<Filter> registration = new
FilterRegistrationBean<>();
final Filter myFilter = new ServicesFilter();
registration.setFilter(myFilter);
registration.addUrlPatterns("/myurl1/*", "/myurl2/*");
return registration;
}
#PostConstruct
public void started() {
//
}
}
My Test Class
**package com.mycmp.prj.pkg3;**
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.mongodb.MongoClient;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyApplication.class)
public class MongoConfigStoreTest {
#Test
public void testConnection() throws Exception {
final MongoClient client = new MongoClient("localhost", 127027);
assertNotNull(client);
assertNotNull(client.getDatabase("localhost"));
}
}
I had to add the hamcrest-all-1.3.jar into classpath to run unit test.
junit 4.12
java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=myTest], {ExactMatcher:fDisplayName=scannerTest(example.JavaTest)], {LeadingIdentifierMatcher:fClassName=example.JavaTest,fLeadingIdentifier=myTest]] from org.junit.internal.requests.ClassRequest#38af3868
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:40)
Check for below conditions:
Have you used org.junit.jupiter.api.Test; instead of org.junit.Test;
for running Junit 4 test cases?
Have you passed an argument to the
test method as shown below:
public void test(String arg){
assertTrue(true);
}
Re-building a project will also work:
mvn clean install
If it is a maven project run eclipse:eclipse as a Maven build.That resolved my problem.
When you use gradle (and you use codium as IDE)
you may need to rebuild it manually, e.g. with ./gradlew build.
Yup, in VSCode Testing view, I often get the horrible red "InitializationError" for my Java JUnit-based JPA tests and could never figure it out. Based on Mohit Basak comment, I changed
#SpringBootTest(classes = {MyApp.class})
public class MyTest {
...
}
to
#SpringBootTest(classes = {com.xyz.MyApp.class})
public class MyTest {
...
}
and so far I think it's working better now. The tests always ran green/complete and even runs fine from command line with gradle build

How to exclude/disable a specific auto-configuration in Spring boot 1.4.0 for #DataJpaTest?

I am using the #DataJpaTest from Spring for my test which will then use H2 as in memory database as described here . I'm also using Flyway for production. However once the test starts FLyway kicks in and reads the SQL file. How can I exclude the FlywayAutoConfiguration and keep the rest as described here in spring documentation in order to let Hibernate create the tables in H2 for me?
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private MyRepository triggerRepository;
}
Have you tried the #OverrideAutoConfiguration annotation?
It says it "can be used to override #EnableAutoConfiguration".
I'm assuming that from there you can somehow exclude FlywayAutoConfiguration
like so:
#EnableAutoConfiguration(exclude=FlywayAutoConfiguration.class)
Adding the dependency on an in-memory database to my build.gradle
e.g. testRuntime "com.h2database:h2:1.4.194"
And adding flyway.enabled=false to application.properties in src/test/resources worked for me.
I am converting an old JDBC app into a spring-data-jpa app and I'm working on the first tests now. I kept seeing a security module instantiation error from spring-boot as it tried to bootstrap the security setup, even though #DataJpaTest should theoretically be excluding it.
My problem with the security module probably stems from the pre-existing implementation which I inherited using PropertySourcesPlaceholderConfigurer (via my PropertySpringConfig import below)
Following the docs here:
http://docs.spring.io/spring-boot/docs/1.4.x/reference/htmlsingle/#test-auto-configuration
and your comments on #LiviaMorunianu's answer, I managed to work my way past every spring-boot exception and get JUnit to run with an auto-configured embedded DB.
My main/production spring-boot bootstrap class bootstraps everything including the stuff I want to exclude from my tests. So instead of using #DataJpaTest, I copied much of what it is doing, using #Import to bring in the centralized configurations that every test / live setup will use.
I also had issues because of the package structure I use, since initially I was running the test which was based in com.mycompany.repositories and it didn't find the entities in com.mycompany.entities.
Below are the relevant classes.
JUnit Test
#RunWith(SpringRunner.class)
#Transactional
#Import({TestConfiguration.class, LiveConfiguration.class})
public class ForecastRepositoryTests {
#Autowired
ForecastRepository repository;
Forecast forecast;
#Before
public void setUp() {
forecast = createDummyForecast(TEST_NAME, 12345L);
}
#Test
public void testFindSavedForecastById() {
forecast = repository.save(forecast);
assertThat(repository.findOne(forecast.getId()), is(forecast));
}
Live Configuration
#Configuration
#EnableJpaRepositories(basePackages = {"com.mycompany.repository"})
#EntityScan(basePackages = {"com.mycompany.entity"})
#Import({PropertySpringConfig.class})
public class LiveConfiguration {}
Test Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestConfiguration {
// lots of bean definitions...
}
PropertySpringConfig
#Configuration
public class PropertySpringConfig {
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
throws IOException {
return new CorePropertySourcesPlaceholderConfigurer(
System.getProperties());
}
}
In my particular case, i needed to disable the FlywayDB on in-memory integration tests. These are using a set of spring annotations for auto-configuring a limited applicationContext.
#ImportAutoConfiguration(value = TestConfig.class, exclude = FlywayAutoConfiguration.class)
the exclude could effectively further limit the set of beans initiated for this test
I had the same problem with my DbUnit tests defined in Spock test classes. In my case I was able to disable the Flyway migration and managed to initialize the H2 test database tables like this:
#SpringBootTest(classes = MyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = ["flyway.enabled=false", "spring.datasource.schema=db/migration/h2/V1__init.sql"])
I added this annotation to my Spock test specification class. Also, I was only able to make it work if I also added the context configuration annotation:
#ContextConfiguration(classes = MyApplication.class)
I resolved the same issue by excluding the autoconfiguration from my application definition, i.e.
#SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
you can also sue the following annotation:
#RunWith(SpringRunner.class)
#DataJpaTest(excludeAutoConfiguration = {MySqlConfiguration.class, ...})
public class TheClassYouAreUnitTesting {
}
You can just disable it in your test yaml file:
flyway.enabled: false

Resources