Spring Boot : java.awt.HeadlessException - java

When we are trying to get the Clipboard instance.
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
Also i have tried to run the Spring boot application by setting the head.
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringBootApplication.class,args);
builder.headless(false).run(args);
we are getting below exception.
java.awt.HeadlessException
at sun.awt.HeadlessToolkit.getSystemClipboard(HeadlessToolkit.java:309)
at com.kpit.ecueditor.core.utils.ClipboardUtility.copyToClipboard(ClipboardUtility.java:57)
Can someone suggest me what i am missing here.
If i run the same clipboard code in simple java application , it is working but not in the spring boot application.

instead of this line
SpringApplication.run(Application.class, args);
use
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
builder.headless(false);
ConfigurableApplicationContext context = builder.run(args);
It will work

I had the same Exception, using Spring Boot 2 in a swing application.
Here is a sample of what worked for me:
In the main class:
//Main.java
#SpringBootApplication
public class Main implements CommandLineRunner {
public static void main(String[] args) {
ApplicationContext contexto = new SpringApplicationBuilder(Main.class)
.web(WebApplicationType.NONE)
.headless(false)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
#Override
public void run(String... args) throws Exception {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setVisible(true);
});
}
}
In the test class, you'll need to set java.awt.headless propety, so that you won't get a java.awt.HeadlessException when testing the code:
//MainTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
public class MainTest {
#BeforeClass
public static void setupHeadlessMode() {
System.setProperty("java.awt.headless", "false");
}
#Test
public void someTest() { }
}
For those who are having this exception using JavaFX this answer might help.

You can also just pass the a JVM parameter when running your application, no code change required:
-Djava.awt.headless=false
Tested on springboot 2.2.5.RELEASE

I was facing same issue, all of the solutions shown here didn't work out.
Finally noticed DB server user id was disabled hence this was happening no code change was really required. This error was hella misleading.
Suggestion for whoever is facing similar to validate stacktrace and if db connection class is getting this error test out database through simple java class/IDE instead of Spring boot.

Related

JavaFX SpringBoot SpringJDBC SQLite CRUD Application - configuration

I'm developing a JavaFX CRUD application with SpringBoot + SpringJDBC + SQLite . I'm using Eclipse IDE.
STORY:
I'm developing this application as StepByStep process. And I achieved JavaFX+SQLite CRUD application with Old School JDBC Connection. But After Integrating SpringBoot + SpringJDBC I get error. I think the error in passing application configuration to all the files.
Main.Class
#SpringBootApplication
public class Main {
public static void main(String[] args) {
Application.launch(MyApplication.class, args);
}
}
AND MyApplication.Class (has no annotation)
public class MyApplication extends Application {
protected ConfigurableApplicationContext applicationContext;
#Override
public void init() throws Exception {
applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
#Override
public void stop() throws Exception {
applicationContext.close();
Platform.exit();
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("ExYouTub");
stage.setOnCloseRequest(x -> {
Platform.exit();
});
stage.setResizable(false);
stage.setScene(new Scene(FXMLLoader.load(getClass().getResource("../Sample.fxml"))));
stage.show();
}
}
AND AppConfig.class
#Configuration
#ConditionalOnClass(DataSource.class)
#Profile("sqlite")
#ComponentScan(basePackages= "com.fz")
#PropertySource("classpath:data/config.properties")
public class AppConfig {
#Autowired
Environment environment;
private final String DB_URL = "fz.db.url";
#Bean
DataSource dataSource() {
final DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl(environment.getProperty(DB_URL));
return driverManagerDataSource;
}
}
AND SampleController.class
#Controller
public class SampleController implements Initializable {
//-- un-necessary lines are ignored to copy
#Autowired
#Qualifier("studentsDAOImpl")
private StudentsDAO studentsDAO;
#Override
public void initialize(URL location, ResourceBundle resources) {
tableViewList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
setColumnProperties();
loadStudentsDetails();
}
private void loadStudentsDetails() {
studentsList.clear();
studentsList.addAll(studentsDAO.getAllStudents()); // this is line 83
tableViewList.setItems(studentsList);
}
}
AND Error report
Caused by: java.lang.NullPointerException
at com.fz.SampleController.loadStudentsDetails(SampleController.java:83)
at com.fz.SampleController.initialize(SampleController.java:78)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
... 17 more
And Up to now my guess on this error is that, the configuration is not working properly - i think so. I need suggestion and help me improve on this.
The default behaviour for FXMLLoader to create the controller instance is to simply instantiate it, which means no dependencies get injected. To get injection, you rather need the Spring ApplicationContext to manage the instance creation.
Josh Long has issued a Spring Tips installment demonstrating how to do this step by step: https://spring.io/blog/2019/01/16/spring-tips-javafx
However, this is a quite manual and repetitive process. This is what https://github.com/rgielen/javafx-weaver tries to solve. You can find a documentation and example code here: https://github.com/rgielen/javafx-weaver/tree/master/samples/springboot-sample
Disclaimer: I created the library, so I'm biased :)

Spring Boot can connect to Cassandra when running as Servlet but not as Command Line

Background: I'm trying to set up a code-based data migration system for our Cassandra database. I don't have a ton of experience with Java, but if this were a .NET project I'd set up the migrations as a different project under the same solution. However, based on guidance from other team members that are more experienced, it was recommended that I include the migrations in the same package as the rest of the application (which I'm fine with). It was also suggested that the easiest method would be to run the migrations via a web API endpoint (which I'm more skeptical of). In the interest of avoiding opening up a potential security vulnerability, I thought I'd take a shot at making a command-line utility to execute the migrations.
I have a Spring Boot web application with an entry point class that looks like this:
#Configuration
#SpringBootApplication
#EnableAutoConfiguration
#EnableCaching
#EnableScheduling
public class MyApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
new MyApplication().configure(new SpringApplicationBuilder(MyApplication.class)).run(args);
}
}
However, I'm trying to add the functionality to run a couple migration scripts that are packaged with this application via the command line (e.g. java -jar MyApplication.jar migrate), so I added the following class:
#Configuration
#SpringBootApplication
#EnableAutoConfiguration
public class MigrationRunner implements CommandLineRunner {
#Autowired
Session session;
#Override
public void run(String[] args)
{
MigrationResources mr = new MigrationResources();
mr.addMigration(...);
mr.addMigration(...);
MigrationEngine.withSession(session).migrate(mr);
}
}
And then updated my entry point class like this:
// annotations
public class MyApplication extends SpringBootServletInitializer {
private final static String MIGRATE_COMMAND = "migrate";
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
if (args.length > 0 && args[0].equalsIgnoreCase(MIGRATE_COMMAND)) {
new SpringApplicationBuilder()
.sources(MigrationRunner.class)
.run(Arrays.copyOfRange(args, 1, args.length));
} else {
new MyApplication().configure(new SpringApplicationBuilder(MyApplication.class)).run(args);
}
}
}
The problem is that when I execute this with the migrate arg, Spring throws this error:
Error creating bean with name 'migrationRunner': Unsatisfied dependency expressed through field 'session'
Error creating bean with name 'session' defined in class path resource [org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.class]: Invocation of init method failed
All host(s) tried for query failed (tried: server022/XX.YY.ZZ.022:9042 (com.datastax.driver.core.exceptions.TransportException: [server022/XX.YY.ZZ.022:9042] Connection has been closed), server022/XX.YY.ZZ.020:9042 (com.datastax.driver.core.exceptions.TransportException: [server020/XX.YY.ZZ.020:9042] Connection has been closed), server020/XX.YY.ZZ.021:9042 (com.datastax.driver.core.exceptions.TransportException: [server020/XX.YY.ZZ.021:9042] Connection has been closed))
Running it without the migrate arg still works fine. I suspect that Spring is simply not picking up the correct certificates for this Cassandra server, even though it appears to be getting all the other configuration properties (server name, keyspace, etc.)
Question: How can I make a Spring Boot servlet that also has a command-line mode and can connect to the configured Cassandra server in both modes?
All you need to do is,
#SpringBootApplication
public class MyApplication
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
You have over complicated the application. If you run the MyApplication.main that will run in port 8080 by default.
Bonus, If you need both to start from same class.
#SpringBootApplication
public class MigrationRunner implements CommandLineRunner {
#Autowired
Session session;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
public void run(String[] args)
{
MigrationResources mr = new MigrationResources();
mr.addMigration(...);
mr.addMigration(...);
MigrationEngine.withSession(session).migrate(mr);
}
}

Spring Boot - Use Application Listener

After starting my spring boot application I want to start an customer process like creating required folders, files, etc. For that I'm using ApplicationListener<ApplicationReadyEvent>. This works like expected. But I'm building my spring application context with SpringApplicationBuilder. Every child notifies that the application is started correctly. So my customer post-process startes even more than one time.
#SpringBootApplication
#EnableConfigurationProperties(value = {StorageProperties.class})
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplicationBuilder parentBuilder
= new SpringApplicationBuilder(Application.class);
parentBuilder.child(Config1.class)
.properties("server.port:1443")
...
.run(args);
parentBuilder.child(Config2.class)
.properties("server.port:2443")
...
.run(args);
}
}
My first idea was, that I can create manuelly a new Bean with #Bean in Config1 for my Event-Listener. But I was not able to overhand the configuration file StorageProperties.class, which is necessary for this class.
Because the Listener has an constructor based dependency injection:
private final Path mPathTo;
public AfterStart(StorageProperties prop) {
this.mPathTo = Paths.get(prob.getPath());
}
How can I be able to start the listener just once per start?
For everyone who is interested in this question. This solution worked for me:
public void onApplicationEvent(ApplicationReadyEvent e) {
if (e.getApplicationContext().getParent == null) {
System.out.println("******************************");
System.out.println("Post-process begins.");
System.out.println("******************************");
}
}

How do you pass program arguments in a #SpringBootTest?

I'm building a spring boot application. I want to run it like this:
java -jar myjar.jar inputFile outputFile
How do I write a #SpringBootTest for this? I imagine that using #SpringBootTest would make Spring fail during startup because some of my code would say, "you need to provide an inputFile and outputFile". Is there a way to pass program arguments when using a #SpringBootTest?
I'm inferring from this answer that I may have to use a SpringApplicationBuilder to do this.
I thought I had the answer but I was wrong. This incorrect information may still be useful to some:
(This information is wrong. I think that some arguments can't be referred to in code as properties, but not all. I still don't know how to get the application arguments in a #SpringBootTest) I was confused because I didn't understand the terminology. The annotation has a parameter for "properties". I thought it was to point it at a property file, but the documentation says:
Properties in form key=value that should be added to the Spring Environment before the test runs.
The other piece of the terminology puzzle is that what I called "program arguments" the Spring docs refer to as "properties".
This is some additional relevant documentation: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-application-arguments
This is a workaround (not an answer). You can do something like this:
private SpringApplicationBuilder subject;
#Before
public void setUp() throws Exception {
subject = new SpringApplicationBuilder(Application.class);
}
#Test
public void requiresInputAndOutput() throws Exception {
thrown.expect(IllegalStateException.class);
subject.run();
}
#Test
public void happyPathHasNoErrors() throws Exception {
subject.run(EXISTING_INPUT_FILE, "does_not_exist");
}
I don't like this very much. It prevents me from using #Autowired elsewhere in my test.
if your program arguments is
--arg1=val1
before springboot version 2.2.0
you can use
#SpringBootTest({"arg1=val1"})
after springboot 2.2.0
you can use
#SpringBootTest(args={"--arg1=val1"})
I had the same issue. Out of the box, the SpringBootContextLoader (used by default with #SpringBootTest) always runs your app without any arguments. However, you can provide your own bootstrapper, which can then in turn provide your own SpringApplication that gets called to run your test. From there, you can override the run(String... args) method to provide whatever arguments you want.
For example, given a simple application:
#SpringBootApplication
public class Main {
public static void main(final String[] args) {
new SpringApplicationBuilder(Main.class).run(args);
}
#Bean
public ApplicationRunner app() {
return args -> System.out.println(args.getOptionNames());
}
}
You can inject test arguments with:
#ContextConfiguration(classes = Main.class)
#ExtendWith(SpringExtension.class)
#BootstrapWith(RestartAppsTest.Bootstrapper.class)
class RestartAppsTest {
static class Bootstrapper extends SpringBootTestContextBootstrapper {
static class ArgumentSupplyingContextLoader extends SpringBootContextLoader {
#Override
protected SpringApplication getSpringApplication() {
return new SpringApplication() {
#Override
public ConfigurableApplicationContext run(String... args) {
return super.run("--restart");
}
};
}
}
#Override
protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) {
return ArgumentSupplyingContextLoader.class;
}
}
#Test
void testRestart() {
//
}
}
It's obviously a bit verbose, but it works. You could clean it up and make a nicer/reusable bootstrapper that looked for your own annotation (or possibly reuse JUnit Jupiter's #Arguments) that declared what arguments to supply (instead of hardcoding them).
You can use #SpringBootTest(classes=Application.class, args ={inputFile, outputFile}) if your app's main method looks a little different like
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
For me working example is
#SpringBootTest(args ={"--env", "test"})
class QuickFixServerAppTest {
#Test
void loadContextTest() {
}
}
is the same as passing the
--env test
argument when starting Spring
Normally you're writing tests for your services; not the boot strapper. Spring Boot will pass command line parameters to your classes - perhaps using the #Value annotation, which in turn will be parameters to your service. Consider testing your services using the SpringRunner. Here's an example from my code base.
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
Neo4jConfigTest.class,
FdTemplate.class,
FdServerIo.class,
MapBasedStorageProxy.class})
#ActiveProfiles({"dev", "fd-auth-test", "fd-client"})
public class TestEntityLinks {
#Autowired
private ContentModelService contentModelService;
#Autowired
private BatchService batchService;
#Test
public void doSomething () { ... }

spring3 annotation with main method

I have following class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:/com/home/app/Home-ctx.xml"})
public class LoginDetailsTest {
public static void main(String[] args) {
new LoginDetailsTest().testLoginDetails();
}
#Inject
#Named(HomeConstants.loginDetailsService)
private LoginDetailsService loginDetailsService;
private List<UserLogin> loginDetails;
#Test
public void testLoginDetails() {
UserLogin login = new UserLogin();
login.setLoginName("test");
login.setLoginPassword("test123");
loginDetails = loginDetailsService.loginDetails(login);
for (UserLogin loginDet : loginDetails) {
System.out.println(loginDet.getLoginName());
System.out.println(loginDet.getLoginPassword());
}
}
}
if i run above code as junit test, then it gives expected result.
If I run as Java application ie main method, then it gives null pointer exception for
loginDetailsService.loginDetails(login). how can run as main method without error?
You still need to do what JUnit does when you "run code as junit test" to bootstrap your application context and dependency injection:
public static void main(String[] args) {
org.junit.runner.JUnitCore.run(LoginDetailsTest.class);
}
The mainis a different thing. Because by instantiating the class by new LoginDetailsTest() it is not build by Spring - there can be no dependency injection.
What you need to do is:
make a new application context appctx.xml for your main method that imports Home-ctx.xml and declare a new bean <bean id="loginDetailsTest" class="LoginDetailsTest"/>
in your main method get an instance of the bean and call testLoginDetails() like this:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("appctx.xml");
LoginDetailsTest loginDetailsTest = (LoginDetailsTest) context.getBean("loginDetailsTest");
loginDetailsTest.testLoginDetails();
}
In general you should separate the JUnit test, main method and business logic.
First things first the reason your test works is (SpringJUnit4ClassRunner), It does a lot but to keep it simple it boot straps the spring container and injects all the dependencies like that you defined in your context file (Home-ctx.xml) including the one you inject into the test case. For more details look at these classes
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/context/TestContextManager.html
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/context/support/DependencyInjectionTestExecutionListener.html
To solve the problem with your main method, You have to load the spring context your self and inject the dependency some thing like this
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/com/home/app/Home-ctx.xml");
new LoginDetailsTest().loginDetailsService = (LoginDetailsService) ctx.getBean(LoginDetailsService.class);
//now your main method should work
new LoginDetailsTest().testLoginDetails();

Categories