Spring Boot Application - Add a private constructor to hide the implicit public one.

8,410 views
Skip to first unread message

Andrew Holland

unread,
Nov 25, 2016, 8:32:00 PM11/25/16
to SonarQube
Hi,

There is a false positive with standard Spring Boot Applications main class on rule 'Utility classes should not have public constructors’.  Is it possible to exclude the rule when SpringApplication.run(...) is called with the same class?

The example below produces the error.

@Controller
@EnableAutoConfiguration
public class SampleController {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleController.class, args);
}
}

Thanks

Andy

Nicolas Peru

unread,
Dec 2, 2016, 4:02:12 AM12/2/16
to Andrew Holland, SonarQube
Hi Andy, 

I am no spring boot expert but why is that a false positive ? AFAI understand : the run call will only get a .class argument in order to read the annotations so, in the end this SampleController class won't be instantiated and thus should not have a public constructor. I may be completely wrong here, so please correct me and explain why it is a false positive.

Thanks

--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sonarqube/FC77CB1B-30DB-4D1E-85F1-2D1AEE98D4FF%40a1dutch.co.uk.
For more options, visit https://groups.google.com/d/optout.
--
Nicolas PERU | SonarSource
Senior Developer
http://sonarsource.com

Brian Sperlongano

unread,
Dec 7, 2016, 12:35:32 PM12/7/16
to SonarQube
Hi Andy,

There is a way that I have found to use Spring boot and be compliant with SQ.  You make two classes - one class which has the main() method, and a separate empty interface that has all of the spring boot annotations.  It gives you a nice clean separation, particularly in cases where you need to do more in the main than simply running SpringApplication.run().

The class with the main() method still should have a private constructor, however.  This ensures that you don't accidentally instantiate a class that has only static parts.  I do believe the finding is correct, even when using Spring Boot.

Andrew Holland

unread,
Dec 8, 2016, 3:48:00 AM12/8/16
to SonarQube
 
Hi Nicolas,

Yes you are correct, its not a false positive in general but in the case of Spring Boot you can’t have a private constructor.

i was just wondering if there could be an exclusion to this rule when the @EnableAutoConfiguration annotation is present or included via another configuration?

Thanks

Andy

On 2 Dec 2016, at 09:01, Nicolas Peru <nicola...@sonarsource.com> wrote:



Andrew Holland

unread,
Dec 8, 2016, 3:55:36 AM12/8/16
to SonarQube
Hi Brian

Thanks for the workaround, it seems way easier to just add the @SuppressWarnings annotation than having to deal with the non issue.

Cheers

Andy

--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.

Nicolas Peru

unread,
Dec 15, 2016, 11:19:36 AM12/15/16
to Andrew Holland, SonarQube
Hi, 

I still don't understand why you can't have a private constructor. 

As per exclusion, the annotation could be handled (but I still need to understand the reason of why it is a FP) but the "other configuration" would have to be a bit more precise thant that to actually think of something.

Cheers, 
--
You received this message because you are subscribed to the Google Groups "SonarQube" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sonarqube+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

dfl...@ippon.fr

unread,
Feb 9, 2017, 11:00:56 AM2/9/17
to SonarQube, ahol...@a1dutch.co.uk
Hi,

With a private constructor, the Spring Boot application can't start. 
We have the following message :

java.lang.IllegalStateException: Cannot load configuration class: ***.service.constructionsite.ConstructionSiteApplication
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:403)
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:249)
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281)
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:125)
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
        at ***.service.constructionsite.ConstructionSiteApplication.main(ConstructionSiteApplication.java:35)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:507)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: No visible constructors in class ***.service.constructionsite.ConstructionSiteApplication
        at org.springframework.cglib.proxy.Enhancer.filterConstructors(Enhancer.java:666)
        at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:567)
        at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
        at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanFactoryAwareGeneratorStrategy.generate(ConfigurationClassEnhancer.java:249)
        at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:329)
        at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:492)
        at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
        at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
        at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
        at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
        at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
        at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
        at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
        at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:337)
        at org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(ConfigurationClassEnhancer.java:135)
        at org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(ConfigurationClassEnhancer.java:107)
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:393)
        ... 16 common frames omitted

Regards,

Denis

dfl...@ippon.fr

unread,
Feb 9, 2017, 11:15:53 AM2/9/17
to SonarQube, ahol...@a1dutch.co.uk, dfl...@ippon.fr
Hi,

An example of code canvas for our Spring Boot Application is :

package ***.service.constructionsite;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.env.Environment;


/**
 * The type ConstructionSite application.
 */
@SpringBootApplication
@EnableConfigurationProperties(***.class)
public class ConstructionSiteApplication {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConstructionSiteApplication.class);
    /**
     * The entry point of application.
     *
     * @param args the input arguments
     * @throws UnknownHostException the unknown host exception
     */
public static void main(String[] args) throws UnknownHostException {
        SpringApplication app = new SpringApplication(ConstructionSiteApplication.class);
        Environment env = app.run(args).getEnvironment();
        ...
...
}
}

Regards,

Denis

Nicolas Peru

unread,
Feb 22, 2017, 10:02:10 AM2/22/17
to dfl...@ippon.fr, SonarQube, ahol...@a1dutch.co.uk
Hi Denis, 

Thank you for the explanation ! 

Cheers, 


For more options, visit https://groups.google.com/d/optout.

dfl...@ippon.fr

unread,
Feb 22, 2017, 12:40:53 PM2/22/17
to SonarQube, dfl...@ippon.fr, ahol...@a1dutch.co.uk
Hi,

Thank you for the creation of the ticket.
Since my previous messages, we use a workaround. As the same way as JHipster, we declare another public method with the @PostConstruct method.
Our new code canvas is :

import com.sgdbf.service.quote.config.DefaultProfileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;

/**
 * The type quote application.
 */
@SpringBootApplication
public class QuoteApplication {

    private static final Logger LOGGER = LoggerFactory.getLogger(QuoteApplication.class);

    private final Environment env;

    public QuoteApplication(Environment env) {
        this.env = env;
    }

    /**
     * The entry point of application.
     *
     * @param args the input arguments
     * @throws UnknownHostException the unknown host exception
     */
    public static void main(String[] args) throws UnknownHostException {
        SpringApplication app = new SpringApplication(QuoteApplication.class);
        DefaultProfileUtil.addDefaultProfile(app);
        Environment env = app.run(args).getEnvironment();
        ...
...
    }

    @PostConstruct
    public void logProfile() {
        LOGGER.info("Application has been launched with profiles: ", env.getActiveProfiles());
    }
}


Regards,

Denis

robert...@gmail.com

unread,
May 24, 2017, 5:54:10 AM5/24/17
to SonarQube
Hi all,

I found this ticket http://jira.codehaus.org/browse/SONARJAVA-223 ... maybe it can be useful.

ciao
Roberto
Reply all
Reply to author
Forward
0 new messages