No value has been specified for property 'mainClassName' - gradle

I am trying to build a project with
apply plugin: 'spring-boot'
But it throws an exception at the step startScripts
:common:compileJava UP-TO-DATE
:common:processResources UP-TO-DATE
:common:classes UP-TO-DATE
:common:jar UP-TO-DATE
:common:findMainClass
:common:startScripts FAILED
FAILURE: Build failed with an exception.
* What went wrong:
A problem was found with the configuration of task ':common:startScripts'.
> No value has been specified for property 'mainClassName'.
But I really do not need a main Class for this module. How should I settle this?

There's an open ticket about this issue on Spring-Boot's GitHub: https://github.com/spring-projects/spring-boot/issues/2679. There are couple things you can do according to discussion:
Remove spring-boot plugin from buildscript section. This will remove special Gradle tasks from build flow.
Assign mainClassName to some random string. It's not pretty but as far as this is not runnable app you probably don't care about main class.
There are some more bulky ways to solve this listed by the link if you want to try them.
Hope this helps.

You need a main method which calls SpringApplication.run(...). Like this:
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
In the Gettings started guide is a paragraph about the main method:
The final part of our application is the main method. This is just a
standard method that follows the Java convention for an application
entry point. Our main method delegates to Spring Boot’s
SpringApplication class by calling run. SpringApplication will
bootstrap our application, starting Spring which will in turn start
the auto-configured Tomcat web server. We need to pass Example.class
as an argument to the run method to tell SpringApplication which is
the primary Spring component. The args array is also passed through to
expose any command-line arguments.
I recommend to create a Application class where it all starts:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But, perhaps you should start with the Quick start guide at first.

I have the following at the end of my build.gradle to define the name of the main class.
I also use gradlew bootjar instead of gradlew build.
bootJar {
mainClassName = 'com.spring.xx.app.App'
}

Related

Spring with Apache Beam

I want to use Spring with Apache Beam that will run on Google Cloud Data flow Runner. Dataflow job should be able to use Spring Runtime application context while executing the Pipeline steps. I want to use Spring feature in my Apache Beam pipeline for DI and other stuff. After browsing hours on google, I couldn't find any post or documentation which shows Spring integration in Apache Beam. So, if anyone has tried spring with Apache beam, please let me know.
In main class i have initialised the spring application context but it is not available while execution of pipeline steps. I get null pointer exception for autowired beans. I guess the problem is, at runtime context is not available to worker threads.
public static void main(String[] args) {
initSpringApplicationContext();
GcmOptions options = PipelineOptionsFactory.fromArgs(args)
.withValidation()
.as(GcmOptions.class);
Pipeline pipeline = Pipeline.create(options);
// pipeline definition
}
I want to inject the spring application context to each of the ParDo functions.
The problem here is that the ApplicationContext is not available on any worker, as the main method is only called when constructing the job and not on any worker machine. Therefore, initSpringApplicationContext is never called on any worker.
I've never tried to use Spring within Apache Beam, but I guess moving initSpringApplicationContext in a static initializer block will lead to your expected result.
public class ApplicationContextHolder {
private static final ApplicationContext CTX;
static {
CTX = initApplicationContext();
}
public static ApplicationContext getContext() {
return CTX;
}
}
Please be aware that this alone shouldn't be considered as a best practice of using Spring within Apache Beam since it doesn't integrate well in the lifecycle of Apache Beam. For example, when an error happens during the initialization of the application context, it will appear in the first place where the ApplicationContextHolder is used. Therefore, I'd recommend to extract initApplicationContext out of the static initializer block and call it explicitly with regards to Apache Beam's Lifecycle. The setup phase would be a good place for this.

Could not find or load main class while trying to run project from IntelliJ

I have downloaded project
git clone http://github.com/jwills/crunch-demo
then imported it into IntelliJ as Maven existing project. Now I am trying to run main function, but failing with error message
Error: Could not find or load main class com.example.WordCount
What is it and how to fix?
UPDATE
If I create new Hello World Maven project from scratch, then it works.
UPDATE 2
If I make any HelloWorld class extends Configured implements Tool, it also stops working:
public class HelloWorld extends Configured implements Tool {
public static void main(String[] args) {
System.out.println("Hello world");
}
#Override public int run(String[] strings) throws Exception {
return 0;
}
}
UPDATE 3
I need explanation from the point of view of IntelliJ: how can it loose ability to find some names in classpath just because of some class extensions?
Configured and Tool classes are not added to the classpath since the scope of the dependencies in pom.xml is configured as provided.
You are not running the class in some container that is providing these dependencies, but directly from the IDE, therefore these classes must be available in the classpath.
To fix the problem remove all the <scope>provided</scope> tags from pom.xml, Import Changes to update the dependencies in the Maven project.
This may be happening because your project is not correctly opened. What do you mean you imported it into the IntelliJ? Please attach an image containing the project explorer from your opened project and I will try to help more.

Problems setting up Spring security in existing MVC project

I'm trying to add Spring security to an existing Spring MVC project. I'm using this as a guide:
http://docs.spring.io/spring-security/site/docs/current/guides/html5//hellomvc.html
However, I can't get the project to display the login screen. I copied SecurityConfig.java and MessageSecurityWebApplicationInitializer.java verbatim, when I turn boot logging to DEBUG, I see this:
o.s.b.c.e.ServletContextInitializerBeans : Created Filter initializer for bean 'springSecurityFilterChain'; order=2147483647, resource=class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]
Which suggests that MessageSecurityWebApplicationInitializer is never being looked at. Sure enough, if I create a default constructor and set a breakpoint, it's never getting hit.
Interestingly, SecurityConfig.configureGlobal is called, which seems like the call that should be setting up the login screen.
So what steps need to happen to make MessageSecurityWebApplicationInitializer do its thing? I'm still trying to understand how Spring handles dependency injection, etc.--what about this class declaration should cause this to get picked up during boot (I would have expected some sort of annotation):
public class MessageSecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
I can't share much other code unfortunately, but this is the Application file:
#ComponentScan(basePackages={"..."})
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, SpringBootWebSecurityConfiguration.class})
#Configuration
public class Application extends SpringBootServletInitializer {
/**
* The main() method is required by the framework.
*
* #param args
* #throws IOException
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
The one thing that the sample has that this project doesn't is the MessageWebApplicationInitializer class, but to me it looks like that functionality should be picked up by my Application class.
Thanks!
You must add annotations #Configuration and #EnableWebSecurity to your MessageSecurityWebApplicationInitializer and take care that its picked up by spring. Than it should work.
So it turns out the problem was these lines in my gradle build:
compile(group: "org.springframework.boot", name: "spring-boot-starter-actuator", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-web", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-test", version: "1.2.3.RELEASE")
compile(group: "org.springframework.boot", name: "spring-boot-starter-jdbc", version: "1.2.3.RELEASE")
It would be great if anyone could shed some insight into why these lines would break the security setup.

Spring boot AMQP and Spring Hadoop together ends up with missing EmbeddedServletContainerFactory bean

I have two small apps, one uses spring-boot-starter-amqp, other uses spring-data-hadoop-boot. I can run them separately without any problems.
When I join them together, app start fails with exception: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
My main class is pretty much generic and it works fine for both of them separately:
#PropertySource("file:conf/app.properties")
#SpringBootApplication
public class Job {
public static void main(String[] args) throws Exception {
SpringApplication.run(Job.class, args);
}
}
I am at lost here. AFAIK #SpringBootApplication contains all annotations needed, including auto configuration and components scanning. I've had no need to configure web environment as I am not using it. Why do I need to do it when both dependencies are in class path, and how do I fix it?
UPDATE
I dug a little bit in the Spring Boot code. Main problem is that SpringApplication.deduceWebEnvironment() automatically detects what kind of environment should be configured based on existence of certain classes in class path.
For web environment two classes are being checked. When both of them are in class path, web environment is detected which requires proper configuration, obviously.
javax.servlet.Servlet
org.springframework.web.context.ConfigurableWebApplicationContext
spring-boot-starter-amqp:1.3.1.RELEASE contains ConfigurableWebApplicationContext, and spring-data-hadoop-boot:2.3.0.RELEASE-cdh5 contains Servlet (in native Hadoop libs).
Now, when run alone, one of above classes is missing in both cases, which results in web environment not being set.
But when I use both of them - both classes can be found. Web environment is detected, false positive, and it requires configuration, which I am not able (and don't want) to provide.
So question now is - can I force non web environment, even when I have those classes in class path? Or is there any other way to solve the issue? (other than excluding them from Gradle dependencies)
Solved.
Following this question: How to prevent spring-boot autoconfiguration for spring-web?
I run application as follows.
#PropertySource("file:conf/app.properties")
#SpringBootApplication
public class Job {
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Job.class).web(false).run(args);
}
}
Answers to above question also suggested to use property spring.main.web_environment=false or annotation #EnableAutoConfiguration(exclude = WebMvcAutoConfiguration.class). Both solutions haven't worked for me. Only programmatic solution works in my case.

Programmatically restart Spring Boot application

I'm using Spring Boot and I've got a use case where user can upload a file which should cause a restart of application (since user's upload is used during creation of multiple beans). I know I can avoid restarting the application, but at the moment - this is what I want.
I've found RestartEndpoint in Spring-Cloud project, but it doesn't seem like ApplicationPreparedEvent is fired. Is there any other way I can programmatically restart Spring Boot application?
The simplest way to do this by calling the refresh() method on the Spring ApplicationContext. This will kill and reload all of your beans, so you should be certain that this occurs only when it is safe for your application to do so.
I have a special case in which my Spring Boot application, which runs on Linux, is required to run as root.
Since I run the application as systemd service, I can restart it like this:
Runtime.getRuntime().exec(new String[] { "/bin/systemctl", "restart", "foo" });
If your application is (hopefully) not required to run as root, a setuid wrapper-script could be used, or better, use sudo.
Check this answer on how to do that:
https://superuser.com/questions/440363/can-i-make-a-script-always-execute-as-root
In your case it might be possible to use the /refresh endpoint (see http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_endpoints) and annotate the beans that depend on the changed configuration with #RefreshScope.
I used the below code to restart my application from the code itself. Closing context using a separate thread will not shut the JVM.
public class DemoApplication {
private static String[] args;
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
DemoApplication.args = args;
context = SpringApplication.run(DemoApplication.class, args);
}
public static void restart() {
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(DemoApplication.class, DemoApplication.args);
});
thread.setDaemon(false);
thread.start();
}

Resources