Spring boot applicaton will not stay up - spring

I created a simple REST Spring boot application. I see it start, but it immediately shutsdown. There is no error in log.
Below is the code and the log.
Code:
#Controller
#ComponentScan
#EnableAutoConfiguration
#RequestMapping("userInfo")
public class UserUpdateService
{
private java.util.logging.Logger logger = Logger.getLogger("UserUpdateService");
#RequestMapping(value="/{userId}", method=RequestMethod.GET, produces = "application/xml; charset=utf-8")
#ResponseBody
String getUserInfo(#PathVariable String userId)
{
String func = "getUserInfo";
logger.entering("UserUpdateService", func);
String retval = "";
return retval;
}
#RequestMapping(value="/{userId}", method=RequestMethod.DELETE, produces = "application/xml; charset=utf-8")
#ResponseBody
String removeUser(#PathVariable String userId)
{
String retval = "";
String func = "removeUser";
logger.entering("UserUpdateService", func);
return retval;
}
#RequestMapping(value="/", method=RequestMethod.PUT, produces = "application/xml; charset=utf-8")
#ResponseBody
String addUser(#WebParam (name = "userId")String userId)
{
String retval = "";
String func = "addUser";
logger.entering("UserUpdateService", func);
return retval;
}
public static void main(String[] args)
{
ApplicationContext ctx = SpringApplication.run(UserUpdateService.class, args);
}
}
Log:
Java HotSpot(TM) Server VM warning: .hotspot_compiler file is present but has been ignored. Run with -XX:CompileCommandFile=.hotspot_compiler to load the file.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.2.1.RELEASE)
- Starting UserUpdateService on localhost with PID 950 (/opt/home/vatsan/MicroSvcs started by vzwadmin in /opt/home/vatsan/MicroSvcs/bin)
- Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#128edf2: startup date [Thu Jan 29 18:59:37 EST 2015]; root of context hierarchy
- Started UserUpdateService in 0.812 seconds (JVM running for 1.806)
- Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#128edf2: startup date [Thu Jan 29 18:59:37 EST 2015]; root of context hierarchy

if you are using maven, check out your pom.xml file, then you will find something like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
it should be changed to this instead:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Related

Is there a way to launch FXGL with SpringBoot?

I need to launch application with fxgl animations with springboot to utilize it's functionality.
I dont really know how to do it.
I tried putting initialization into different init() methods of the inheritor of the GameApplication.
I tried it like this:
#Override
protected void onPreInit() {
context = SpringApplication.run(getClass(), savedArgs);
context.getAutowireCapableBeanFactory().autowireBean(this);
super.onPreInit();
}
Or tried to mimic web version:
public class App extends Application {
private ConfigurableApplicationContext applicationContext;
#Override
public void init() {
String[] args = getParameters().getRaw().toArray(new String[0]);
this.applicationContext = new SpringApplicationBuilder()
.sources(DiplomaBaseApplication.class)
.run(args);
}
#Override
public void stop() {
this.applicationContext.close();
Platform.exit();
}
#Override
public void start(Stage stage) {
GameApplication gameApplication = new SimulationApplication();
GameApplication.embeddedLaunch(gameApplication);
}
}
#SpringBootApplication
public class DiplomaBaseApplication {
public static void main(String[] args) {
Application.launch(App.class, args);
}
}
Using javafx-weaver-spring-boot-starter.
The application started, but spring initialization ended to early end spring features and beans doesn't work:
22:08:38.879 [JavaFX Application Thread] INFO Engine - FXGL-11.17 (16.07.2021 15.46) on WINDOWS (J:11.0.10 FX:16)
22:08:38.879 [JavaFX Application Thread] INFO Engine - Source code and latest versions at: https://github.com/AlmasB/FXGL
22:08:38.880 [JavaFX Application Thread] INFO Engine - Join the FXGL chat at: https://gitter.im/AlmasB/FXGL
22:08:39.418 [FXGL Background Thread 1 ] INFO FXGLApplication - FXGL initialization took: 0,325 sec
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.7)
2022-05-13 22:08:39.900 INFO 31948 --- [lication Thread] o.s.boot.SpringApplication : Starting application using Java 11.0.10 on DESKTOP-2DKK20I with PID 31948 (started by pro56 in C:\Users\pro56\Desktop\Course)
2022-05-13 22:08:39.903 INFO 31948 --- [lication Thread] o.s.boot.SpringApplication : No active profile set, falling back to 1 default profile: "default"
2022-05-13 22:08:39.985 INFO 31948 --- [lication Thread] o.s.boot.SpringApplication : Started application in 0.425 seconds (JVM running for 1.813)
22:08:40.056 [FXGL Background Thread 1 ] INFO FXGLApplication - Game initialization took: 0,024 sec
22:08:40.852 [FXGL Background Thread 2 ] INFO UpdaterService - Your current version: 11.17
22:08:40.852 [FXGL Background Thread 2 ] INFO UpdaterService - Latest stable version: 17.1
I'm not exactly sure why this did not work for you. I tried it and it worked fine for me.
This warning is generated:
Unsupported JavaFX configuration: classes were loaded from 'unnamed module #307f6b8c'
I guess that is just how fxgl works, it runs JavaFX off the classpath in an unsupported configuration by default. I see from the FXGL documentation that it can be used as a module, so I guess in that configuration it will run a supported configuration using JavaFX modules rather than off the classpath. However, SpringBoot isn't currently coded to use the modulepath (that will happen with SpringBoot 3, I believe). So, for now, it is probably best to run everything in the unsupported configuration as demonstrated by this example.
Although in the example I placed a main method in the DemoSpringApplication for testing, the actual main class to run is not that one, it is instead the BasicSpringGameApp which extends the FXGL GameApplication.
The BasicSpringGameApp will call the SpringApplication static method to run the Spring application (which will create an instance of the Spring application).
The Spring application is separate from the FXGL GameApplication (which is internally separate from the JavaFX Application), so all of those things have different instances (just one of each), applying a separation of concerns.
src/main/java/com/example/glboot/BasicSpringGameApp.java
Extends the FXGL GameApplication. The FXGL GameApplication will (internally) launch a JavaFX application. This example will also run a spring application so that spring services will be available. The spring context is autowired into the GameApplication class so that spring services are available for use within the GameApplication class. The use of a Spring inject service is demonstrated by making calls to the UserService, which is a Spring service.
package com.example.glboot;
import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.dsl.FXGL;
import javafx.scene.control.Label;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
public class BasicSpringGameApp extends GameApplication {
private ConfigurableApplicationContext springContext;
#Autowired
UserService userService;
#Override
protected void initSettings(GameSettings settings) {
settings.setWidth(200);
settings.setHeight(150);
settings.setTitle("Game App");
springContext =
new SpringApplicationBuilder(DemoSpringApplication.class)
.web(WebApplicationType.NONE)
.run();
springContext
.getAutowireCapableBeanFactory()
.autowireBeanProperties(
this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,
true
);
}
#Override
protected void initGame() {
String welcomeText =
"hello, " + userService.getUsername() + "\n" + userService.getWelcomeMessage();
FXGL.entityBuilder()
.at(50, 50)
.view(new Label(welcomeText))
.buildAndAttach();
}
public static void main(String[] args) {
launch(args);
}
}
src/main/resources/DemoSpringApplication.java
SpringBoot application, configures and starts up a spring services via the SpringBoot framework.
package com.example.glboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoSpringApplication {
public static void main(String[] args) {
SpringApplication.run(DemoSpringApplication.class, args);
}
}
src/main/java/com/example/glboot/UserService.java
An example user information spring service with some injected values from the spring context and application configuration properties.
package com.example.glboot;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
#Service
public class UserService {
#Value("${user.name}")
private String username;
#Value("${welcome.message}")
private String welcomeMessage;
public String getUsername() {
return username;
}
public String getWelcomeMessage() {
return welcomeMessage;
}
}
src/main/resoruces/application.properties
Spring configuration properties.
welcome.message=Welcome to FXGL Boot
pom.xml
Maven project file.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>glboot</artifactId>
<version>1.0-SNAPSHOT</version>
<name>glboot</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>18.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>18.0.1</version>
</dependency>
<dependency>
<groupId>com.github.almasb</groupId>
<artifactId>fxgl</artifactId>
<version>17</version>
<exclusions>
<exclusion>
<groupId>org.openjfx</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version>
<configuration>
<source>18</source>
<target>18</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
console output
/Users/js732745/Library/Java/JavaVirtualMachines/openjdk-18.0.1.1/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=59335:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/js732745/dev/glboot/target/classes:/Users/js732745/.m2/repository/org/openjfx/javafx-controls/18.0.1/javafx-controls-18.0.1.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-controls/18.0.1/javafx-controls-18.0.1-mac.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-graphics/18.0.1/javafx-graphics-18.0.1.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-graphics/18.0.1/javafx-graphics-18.0.1-mac.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-base/18.0.1/javafx-base-18.0.1.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-base/18.0.1/javafx-base-18.0.1-mac.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-fxml/18.0.1/javafx-fxml-18.0.1.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-fxml/18.0.1/javafx-fxml-18.0.1-mac.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-media/18.0.1/javafx-media-18.0.1.jar:/Users/js732745/.m2/repository/org/openjfx/javafx-media/18.0.1/javafx-media-18.0.1-mac.jar:/Users/js732745/.m2/repository/com/github/almasb/fxgl/17/fxgl-17.jar:/Users/js732745/.m2/repository/com/github/almasb/fxgl-core/17/fxgl-core-17.jar:/Users/js732745/.m2/repository/com/gluonhq/attach/audio/4.0.9/audio-4.0.9.jar:/Users/js732745/.m2/repository/com/github/almasb/fxgl-io/17/fxgl-io-17.jar:/Users/js732745/.m2/repository/com/gluonhq/attach/storage/4.0.9/storage-4.0.9.jar:/Users/js732745/.m2/repository/com/gluonhq/attach/util/4.0.9/util-4.0.9.jar:/Users/js732745/.m2/repository/com/github/almasb/fxgl-entity/17/fxgl-entity-17.jar:/Users/js732745/.m2/repository/com/github/almasb/fxgl-scene/17/fxgl-scene-17.jar:/Users/js732745/.m2/repository/com/github/almasb/fxgl-gameplay/17/fxgl-gameplay-17.jar:/Users/js732745/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.13.2/jackson-annotations-2.13.2.jar:/Users/js732745/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.13.2.1/jackson-databind-2.13.2.1.jar:/Users/js732745/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.13.2/jackson-core-2.13.2.jar:/Users/js732745/.m2/repository/com/gluonhq/attach/lifecycle/4.0.9/lifecycle-4.0.9.jar:/Users/js732745/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.5.32/kotlin-stdlib-1.5.32-modular.jar:/Users/js732745/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/Users/js732745/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.21/kotlin-stdlib-common-1.6.21.jar:/Users/js732745/.m2/repository/org/springframework/boot/spring-boot-starter/2.6.7/spring-boot-starter-2.6.7.jar:/Users/js732745/.m2/repository/org/springframework/boot/spring-boot/2.6.7/spring-boot-2.6.7.jar:/Users/js732745/.m2/repository/org/springframework/spring-context/5.3.19/spring-context-5.3.19.jar:/Users/js732745/.m2/repository/org/springframework/spring-aop/5.3.19/spring-aop-5.3.19.jar:/Users/js732745/.m2/repository/org/springframework/spring-beans/5.3.19/spring-beans-5.3.19.jar:/Users/js732745/.m2/repository/org/springframework/spring-expression/5.3.19/spring-expression-5.3.19.jar:/Users/js732745/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.6.7/spring-boot-autoconfigure-2.6.7.jar:/Users/js732745/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.6.7/spring-boot-starter-logging-2.6.7.jar:/Users/js732745/.m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar:/Users/js732745/.m2/repository/ch/qos/logback/logback-core/1.2.11/logback-core-1.2.11.jar:/Users/js732745/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.17.2/log4j-to-slf4j-2.17.2.jar:/Users/js732745/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar:/Users/js732745/.m2/repository/org/slf4j/jul-to-slf4j/1.7.36/jul-to-slf4j-1.7.36.jar:/Users/js732745/.m2/repository/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/js732745/.m2/repository/org/springframework/spring-core/5.3.19/spring-core-5.3.19.jar:/Users/js732745/.m2/repository/org/springframework/spring-jcl/5.3.19/spring-jcl-5.3.19.jar:/Users/js732745/.m2/repository/org/yaml/snakeyaml/1.29/snakeyaml-1.29.jar:/Users/js732745/.m2/repository/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar com.example.glboot.BasicSpringGameApp
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.7)
2022-05-13 15:54:30.381 INFO 32226 --- [ main] com.example.glboot.BasicSpringGameApp : Starting BasicSpringGameApp using Java 18.0.1.1 on C02ZX2NFMD6T with PID 32226 (/Users/js732745/dev/glboot/target/classes started by js732745 in /Users/js732745/dev/glboot)
2022-05-13 15:54:30.384 INFO 32226 --- [ main] com.example.glboot.BasicSpringGameApp : No active profile set, falling back to 1 default profile: "default"
2022-05-13 15:54:30.772 INFO 32226 --- [ main] com.example.glboot.BasicSpringGameApp : Started BasicSpringGameApp in 0.675 seconds (JVM running for 0.988)
2022-05-13 15:54:30.835 WARN 32226 --- [JavaFX-Launcher] javafx : Unsupported JavaFX configuration: classes were loaded from 'unnamed module #307f6b8c'
15:54:31.118 [JavaFX Application Thread] INFO Engine - FXGL-17 (31.12.2021 18.16) on MAC (J:18.0.1.1 FX:18.0.1)
15:54:31.119 [JavaFX Application Thread] INFO Engine - Source code and latest versions at: https://github.com/AlmasB/FXGL
15:54:31.119 [JavaFX Application Thread] INFO Engine - Ask questions and discuss at: https://github.com/AlmasB/FXGL/discussions
15:54:31.119 [JavaFX Application Thread] INFO Engine - Join the FXGL chat at: https://gitter.im/AlmasB/FXGL
15:54:31.534 [FXGL Background Thread 1 ] WARN FXGL.DefaultMenu - FXGLDefaultMenu is not designed for resolutions < 800x600
15:54:31.686 [FXGL Background Thread 1 ] INFO FXGLApplication - FXGL initialization took: 0.399 sec
15:54:31.757 [FXGL Background Thread 4 ] INFO FXGLApplication - Game initialization took: 0.005 sec
15:54:32.035 [FXGL Background Thread 2 ] INFO UpdaterService - Your current version: 17
15:54:32.036 [FXGL Background Thread 2 ] INFO UpdaterService - Latest stable version: 17.1

Unable to execute any query using Oracle R2DBC driver with Spring Data reactive repositories

I'm using SpringData Reactive Repositories for the first time.
I've been going over the official documentation and I created a basic CRUD API to use them.
I started with H2, just for simplicity, and everything works as expected.
When I try to create a new entity, everything works:
% curl -v -# -X POST http://localhost:8080/wallet/
* Trying ::1:8080...
* Connected to localhost (::1) port 8080 (#0)
> POST /wallet/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.77.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 201 Created
< Content-Type: application/json
< Content-Length: 57
<
* Connection #0 to host localhost left intact
{"id":"6cccd902-01a4-4a81-8166-933b2a109ecc","balance":0}
The code is pretty simple (as usually with SpringData Repositories):
import com.jfcorugedo.reactivedemo.wallet.model.Wallet;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface WalletRepository extends ReactiveCrudRepository<Wallet, String> {
}
And the controller:
import com.jfcorugedo.reactivedemo.wallet.dao.WalletRepository;
import com.jfcorugedo.reactivedemo.wallet.model.Wallet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import java.math.BigDecimal;
import static org.springframework.data.relational.core.query.Query.query;
#RestController
#RequestMapping("wallet")
#Slf4j
public class WalletController {
private WalletRepository walletRepository;
#Autowired
private R2dbcEntityTemplate template;
public WalletController(WalletRepository walletRepository) {
this.walletRepository = walletRepository;
}
#GetMapping("{id}")
public Mono<ResponseEntity<Wallet>> get(#PathVariable("id") String id) {
return walletRepository
.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
#GetMapping("count")
public Mono<ResponseEntity<Long>> count() {
return walletRepository
.count()
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
#PostMapping
public Mono<ResponseEntity<Wallet>> create() {
return walletRepository
.save(Wallet.empty())
.map(w -> ResponseEntity.status(201).body(w));
}
#PostMapping("/entityTemplate")
public Mono<ResponseEntity<Wallet>> insert() {
log.info("Inserting using R2dbcEntityTemplate");
return template.insert(new Wallet(null, BigDecimal.ZERO))
.map(ResponseEntity::ok);
}
}
The DTO is also quite simple:
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.annotation.Id;
import java.math.BigDecimal;
#AllArgsConstructor
#Getter
public class Wallet {
#Id
private String id;
private BigDecimal balance;
public static Wallet empty() {
return new Wallet(null, BigDecimal.ZERO);
}
public Wallet withId(String id) {
return new Wallet(id, this.balance);
}
}
Then I check in the documentation that Oracle is also supported.
And I went over the official Oracle driver documentation.
It is true that this driver is under development, so it is not production-ready.
However I clone the repository and I try to execute some tests over my local Oracle instance and everything works well.
Here is the code I execute using Oracle driver directly:
String r2dbcUrl = "r2dbc:oracle://?oracleNetDescriptor="+DESCRIPTOR;
Mono.from(ConnectionFactories.get(ConnectionFactoryOptions.parse(r2dbcUrl)
.mutate()
.option(ConnectionFactoryOptions.USER, USER)
.option(ConnectionFactoryOptions.PASSWORD, PASSWORD)
.build())
.create())
.flatMapMany(connection ->
Mono.from(connection.createStatement(
"INSERT INTO WALLET (ID, BALANCE) VALUES ('" + UUID.randomUUID().toString() + "', 0)")
.execute())
.flatMapMany(result ->
result.map((row, metadata) -> row.get(0, String.class)))
.concatWith(Mono.from(connection.close()).cast(String.class)))
.toStream()
.forEach(System.out::println);
// A descriptor may also be specified as an Option
Mono.from(ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(ConnectionFactoryOptions.DRIVER, "oracle")
.option(Option.valueOf("oracleNetDescriptor"), DESCRIPTOR)
.option(ConnectionFactoryOptions.USER, USER)
.option(ConnectionFactoryOptions.PASSWORD, PASSWORD)
.build())
.create())
.flatMapMany(connection ->
Mono.from(connection.createStatement(
"SELECT * from wallet")
.execute())
.flatMapMany(result ->
result.map((row, metadata) -> row.get(0, String.class)))
.concatWith(Mono.from(connection.close()).cast(String.class)))
.toStream()
.forEach(System.out::println);
I'm using the code Oracle developers provide in the sample folder.
After executing this code, everything works and a new row is created in my WALLET table.
Finally I try to do the same in SpringData.
I used exactly the same DESCRIPTOR, USER and PASSWORD to connect to Oracle.
This is the configuration class I'm using to get the ConnectionFactory:
package com.jfcorugedo.reactivedemo.config;
import com.jfcorugedo.reactivedemo.wallet.model.Wallet;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.mapping.event.BeforeConvertCallback;
import reactor.core.publisher.Mono;
import java.util.UUID;
#Configuration
#ConditionalOnProperty(name = "dababase.vendor", havingValue = "oracle")
#Slf4j
public class OracleR2dbcConfig extends AbstractR2dbcConfiguration {
#Value("${database.host:localhost}")
private String host;
#Value("${database.port:1521}")
private int port;
#Value("${database.serviceName}")
private String serviceName;
#Override
#Bean("r2dbcConnectionFactory")
public ConnectionFactory connectionFactory() {
String descriptor = "(DESCRIPTION=" +
"(ADDRESS=(HOST=" + host + ")(PORT=" + port + ")(PROTOCOL=tcp))" +
"(CONNECT_DATA=(SERVICE_NAME=" + serviceName + ")))";
log.info("Creating connection factory with descriptor " + descriptor);
String r2dbcUrl = "r2dbc:oracle://?oracleNetDescriptor="+descriptor;
return ConnectionFactories.get(ConnectionFactoryOptions.parse(r2dbcUrl)
.mutate()
.option(ConnectionFactoryOptions.USER, "jfcorugedo")
.option(ConnectionFactoryOptions.PASSWORD, System.getenv("DB_PASSWORD"))
.build());
}
#Bean
BeforeConvertCallback<Wallet> idGenerator() {
return (entity, table) -> entity.getId() == null ? Mono.just(entity.withId(UUID.randomUUID().toString())) : Mono.just(entity);
}
}
It is pretty similar to the one I used in the other project:
private static final String DESCRIPTOR = "(DESCRIPTION=" +
"(ADDRESS=(HOST="+HOST+")(PORT="+PORT+")(PROTOCOL=tcp))" +
"(CONNECT_DATA=(SERVICE_NAME="+SERVICE_NAME+")))";
...
String r2dbcUrl = "r2dbc:oracle://?oracleNetDescriptor="+DESCRIPTOR;
Mono.from(ConnectionFactories.get(ConnectionFactoryOptions.parse(r2dbcUrl)
.mutate()
.option(ConnectionFactoryOptions.USER, USER)
.option(ConnectionFactoryOptions.PASSWORD, PASSWORD)
.build())
.create())
...
After switching to Oracle, SpringBoot application started without any error:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-05 12:48:22.891 INFO 99453 --- [ main] c.j.r.ReactiveDemoApplication : Starting ReactiveDemoApplication using Java 11.0.10 on APM3LC02CH2VNMD6R with PID 99453 (/Users/lp68ba/Developer/personal/reactive-demo/target/classes started by lp68ba in /Users/lp68ba/Developer/personal/reactive-demo)
2021-08-05 12:48:22.892 INFO 99453 --- [ main] c.j.r.ReactiveDemoApplication : No active profile set, falling back to default profiles: default
2021-08-05 12:48:23.165 INFO 99453 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-08-05 12:48:23.214 INFO 99453 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 45 ms. Found 1 R2DBC repository interfaces.
2021-08-05 12:48:23.554 INFO 99453 --- [ main] c.j.r.config.OracleR2dbcConfig : Creating connection factory with descriptor (DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=ORCLCDB)))
2021-08-05 12:48:24.129 INFO 99453 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080
2021-08-05 12:48:24.142 INFO 99453 --- [ main] c.j.r.ReactiveDemoApplication : Started ReactiveDemoApplication in 1.466 seconds (JVM running for 2.021)
However now when I try to execute any operation, the connections remains open and nothing happens:
% curl -v -# -X POST http://localhost:8080/wallet/
* Trying ::1:8080...
* Connected to localhost (::1) port 8080 (#0)
> POST /wallet/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.77.0
> Accept: */*
>
In the logs of the application I can see this trace:
2021-08-05 13:08:20.735 DEBUG 144 --- [nPool-worker-19] o.s.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [INSERT INTO WALLET (ID, BALANCE) VALUES (:P0_id, :P1_balance)]
However the execution never ends, and nothing is created in the database.
I've tried with both: Spring Data Reactive Repositories and R2DBCEntityTemplate with same result.
I've generated a custom version of the Oracle R2DBC Driver with some traces, and this is what I've got:
Using Oracle R2DBC Driver directly (everything works):
Creating OracleConnectionFactoryImpl with options: ConnectionFactoryOptions{options={driver=oracle, oracleNetDescriptor=(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=ORCLCDB))), password=REDACTED, user=jfcorugedo}}
Oracel reactive adapter obtained: oracle.r2dbc.impl.OracleReactiveJdbcAdapter#c33b74f
Datasource obtained: oracle.jdbc.pool.OracleDataSource#696da30b
Creating a new connection
using adatper y datasource to create a new connection
Creating a OracleConnectionImpl with JDBC connection oracle.jdbc.driver.T4CConnection#10f7f7de
createStatement(sql): INSERT INTO WALLET (ID, BALANCE) VALUES ('9a3ab3db-ec38-4544-ac87-4e1a4ad40343', 0)
close()
Using SpringData Reactive Repositories (the connection get stuck and nothing happens):
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.3)
2021-08-05 13:12:49.557 INFO 304 --- [ main] c.j.r.ReactiveDemoApplication : Starting ReactiveDemoApplication using Java 11.0.10 on APM3LC02CH2VNMD6R with PID 304 (/Users/lp68ba/Developer/personal/reactive-demo/target/classes started by lp68ba in /Users/lp68ba/Developer/personal/reactive-demo)
2021-08-05 13:12:49.559 INFO 304 --- [ main] c.j.r.ReactiveDemoApplication : No active profile set, falling back to default profiles: default
2021-08-05 13:12:49.849 INFO 304 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-08-05 13:12:49.891 INFO 304 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 38 ms. Found 1 R2DBC repository interfaces.
2021-08-05 13:12:50.208 INFO 304 --- [ main] c.j.r.config.OracleR2dbcConfig : Creating connection factory with descriptor (DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=ORCLCDB)))
Creating OracleConnectionFactoryImpl with options: ConnectionFactoryOptions{options={driver=oracle, oracleNetDescriptor=(DESCRIPTION=(ADDRESS=(HOST=localhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=ORCLCDB))), password=REDACTED, user=jfcorugedo}}
Oracel reactive adapter obtained: oracle.r2dbc.impl.OracleReactiveJdbcAdapter#5f172d4a
Datasource obtained: oracle.jdbc.pool.OracleDataSource#934b52f
2021-08-05 13:12:50.736 INFO 304 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080
2021-08-05 13:12:50.745 INFO 304 --- [ main] c.j.r.ReactiveDemoApplication : Started ReactiveDemoApplication in 1.417 seconds (JVM running for 4.428)
Creating a new connection
using adatper y datasource to create a new connection
Creating a OracleConnectionImpl with JDBC connection oracle.jdbc.driver.T4CConnection#42dce884
2021-08-05 13:12:54.481 DEBUG 304 --- [nPool-worker-19] o.s.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [INSERT INTO WALLET (ID, BALANCE) VALUES (:P0_id, :P1_balance)]
OracleConnectionImpl#createStatement(sql): INSERT INTO WALLET (ID, BALANCE) VALUES (:P0_id, :P1_balance)
Creating OracleStatementImpl with SQL: INSERT INTO WALLET (ID, BALANCE) VALUES (:P0_id, :P1_balance)
OracleConnectionImpl#close()
I have no idea why the execution is getting stuck with SpringData. The connection seems to be ok and I'm using exactly the same parameters here than I used with Oracle Driver directly.
Does someone have a working example using SpringData R2DBC repositories and Oracle R2DBC Driver?
You can check the code in this repository.
For now, stick with version 0.1.0 of Oracle R2DBC when programming with Spring Data.
The newer versions of Oracle R2DBC implement version 0.9.0.M1 of the R2DBC SPI, which is not currently supported by Spring Data. This was confirmed in a GitHub discussion:
https://github.com/oracle/oracle-r2dbc/issues/30#issuecomment-862989986
Once I rolled back to version 0.1.0 of Oracle R2DBC, I was able to get the demo application working.
I had to refactor OracleR2dbcConfig.java because support for Oracle Net Descriptors wasn't added until after 0.1.0. A plain URL will work fine to configure a host, port, and service name:
public ConnectionFactory connectionFactory() {
String url =
String.format("r2dbc:oracle://%s:%d/%s", host, port, serviceName);
log.info("Creating connection factory with URL:" + url);
return ConnectionFactories.get(ConnectionFactoryOptions.parse(url)
.mutate()
.option(ConnectionFactoryOptions.USER, user)
.option(ConnectionFactoryOptions.PASSWORD, System.getenv("DB_PASSWORD"))
.build());
}
Also, I had to manually create the table before executing the test with curl:
create table wallet (id VARCHAR2(256), balance NUMBER);
I thought Spring Data usually creates tables automatically, so I'm not sure why I had to do this manually. If the table isn't created, then the INSERT will fail with an error indicating that the wallet table doesn't exist:
ORA-04043: object WALLET does not exist
After these changes, it seems like the curl command is going through ok:
curl -v -# -X POST http://localhost:8080/wallet/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /wallet/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 201 Created
< Content-Type: application/json
< Content-Length: 57
<
* Connection #0 to host localhost left intact
{"id":"2bcecf46-05eb-46b4-90ec-cfacff2bbaa8","balance":0}* Closing connection 0

# WebMvcTest loading application context

I have a GreetingController
#Controller
public class GreetingController {
#RequestMapping("/greeting")
public #ResponseBody String greeting() {
return "Hello, same to you";
}
}
and GreetingControllerTest
#WebMvcTest(GreetingController.class)
public class WebMockTest {
#Autowired
private MockMvc mockMvc;
#Test
public void greetingShouldReturnMessageFromService() throws Exception {
this.mockMvc.perform(get("/greeting")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, same to you")));
}
}
I am running the test in intelliJ hoping that it will not load the application context, but it starts with launching the application.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
{"thread":"main","level":"INFO","loggerName":..........
As per spring doc we can narrow the tests to only the web layer by using #WebMvcTest. Does this mean that it still loads the application context? Or maybe I did not understand it correctly.
With #WebMvcTest you still get an application context, but not the full application context.
The started Spring Test Context only contains beans that are relevant for testing your Spring MVC components: #Controller, #ControllerAdvice, Converter, Filter, WebMvcConfigurer.
Injecting MockMvc using #Autowired MockMvc mockMvc; also indicates that you are working with a Spring context and the JUnit Jupiter extension (#ExtendWith(SpringExtension.class which is part of #WebMvcTest) takes care to resolve your fields by retrieving them from the Test context.
If you still don't want a Spring Test context to be started, you can write a unit test using only JUnit and Mockito. With such tests, you would only be able to verify the business logic of your controller and not things like: correct HTTP response, path variable and query parameter resolving, exception handling with different HTTP status, etc.
You can read more on the different Spring Boot Test slices here and on how to use MockMvc to test your web layer.

SpringBoot and log4j2 - application context loaded twice when SpringApplication.run()

I want to use Spring boot and log4j2.
I have this pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
This is my main class:
#Component("batchLauncher")
#Import({ MyConfiguration.class })
public class MyLauncher implements CommandLineRunner {
private static Logger log = LogManager.getLogger(MyLauncher.class);
#Autowired
MyController myController;
public static void main(String[] args) {
log.info("STARTING");
SpringApplication.run(MyLauncher.class, args);
log.info("FINISHED");
}
#Override
public void run(String... args) throws Exception {
log.info("START Batch");
MyController.start();
log.info("END Batch");
}
}
I launch the jar with this option:
-Dlog4j.configurationFile=C:\log4j2.properties
When the application start, the console show me:
DEBUG StatusLogger Reconfiguration complete for context[name=18b4aac2] at URI C:\log4j2.properties (org.apache.logging.log4j.core.LoggerContext#72057ecf) with optional ClassLoader: null
DEBUG StatusLogger Shutdown hook enabled. Registering a new one.
DEBUG StatusLogger LoggerContext[name=18b4aac2, org.apache.logging.log4j.core.LoggerContext#72057ecf] started OK.
2019-02-08 14:57:31.047 INFO [main] [it.batch.MyLauncher] [main] [it.batch.MyLauncher.main] - STARTING THE APPLICATION
DEBUG StatusLogger Using configurationFactory org.apache.logging.log4j.core.config.ConfigurationFactory$Factory#6c80d78a
DEBUG StatusLogger Not in a ServletContext environment, thus not loading WebLookup plugin.
DEBUG StatusLogger Loaded configuration from
...
DEBUG StatusLogger LoggerContext[name=18b4aac2, org.apache.logging.log4j.core.LoggerContext#72057ecf] started OK with configuration XmlConfiguration[location=jar:file:/C:/Users/G0426/.m2/repository/org/springframework/boot/spring-boot/2.1.2.RELEASE/spring-boot-2.1.2.RELEASE.jar!/org/springframework/boot/logging/log4j2/log4j2.xml].
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.2.RELEASE)
2019-02-08 14:57:31.753 INFO 13496 --- [ main] i.f.c.c.o.b.Info
As you can see from logs, log4j2 load my log4j properties file until the line
SpringApplication.run(MyLauncher.class, args);
The previous line is writed in log file, after that running SpringApplication.run(...), a second instance/context is loaded and log4j2 start logging using the default configuration located at:
file:/C:/Users/G0426/.m2/repository/org/springframework/boot/spring-boot/2.1.2.RELEASE/spring-boot-2.1.2.RELEASE.jar!/org/springframework/boot/logging/log4j2/log4j2.xml
What I am doing wrong?
Thanks.
SpringApplication.run(MyLauncher.class, args); is THE starting point of a Spring application. Spring has no control over anything logged before its execution.
Hence the behavior is appropriate considering Spring based logging configuration kicks in only after its context is loaded. Also, Spring Boot uses logging.config property to load the logging configuration.
You can try setting -Dlogging.config=C:\log4j.properties.
See Spring Boot Documentation for further details.

Spring boot: Start an application automatically when Webshere Application Server starts?

Assume I have a SpringBoot Application deployed as a WAR to Websphere Application Server (WAS). This WAR contains a daemon, so it must start straight away when WAS starts (and only once).
However, I still need to activate the SpringBoot Servlet by doing a http request.
Now I understand that the concept of servlets is to act on http requests, I still want to get it auto started on appserver start. This makes my daemon portable from standalone jar/main to war/webapp.
I tried a ServletContextListener, but the contextInitalized also get only called at the first http request.
I do not have a web.xml (servlet 3).
Code:
#SpringBootApplication
#WebListener
public class DemoApplication extends SpringBootServletInitializer implements ServletContextListener {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.err.println("ONSTARTUP");
super.onStartup(servletContext);
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DemoApplication.class);
}
#Override
public void contextInitialized(ServletContextEvent sce) {
System.err.println("contextInitialized");
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
//
}
}
and:
#Component
public class DemoRunner implements ApplicationRunner {
#Override
public void run(ApplicationArguments arg0) throws Exception {
System.err.println("I AM RUNNING");
}
}
When I start WAS I first get this:
Launching defaultServer (WebSphere Application Server
16.0.0.2/wlp-1.0.13.cl160220160526-2258) on Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_79-b15 (en_US)
[...]
[AUDIT ] CWWKT0016I: Web application available (default_host): http://localhost:9080/demo/
[AUDIT ] CWWKZ0001I: Application test started in 17,282 seconds.
To get my Spring Boot application starting, I first need to visit this link (http:/localhost:9080/demo/). Then it starts rolling, starting with the startup method as you can see in the log. But how can I get this starting without doing a http request?
[err] ONSTARTUP
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.0.RELEASE)
2016-09-02 10:45:52.670 INFO 23716 --- [dPool-thread-48] com.example.DemoApplication : Starting DemoApplication on [...]
2016-09-02 10:45:58.019 INFO 23716 --- [dPool-thread-48] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
[...]
[err] I AM RUNNING
[...]
2016-09-02 10:45:58.093 INFO 23716 --- [dPool-thread-48] com.example.DemoApplication : Started DemoApplication in 6.372 seconds (JVM running for 31.549)
[...]
[err] contextInitialized
[err] contextInitialized
You can change the loadOnStartup by customize the spring dispatch servlet, here is the sample question and you can use the code
#Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
return new BeanFactoryPostProcessor() {
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition bean = beanFactory.getBeanDefinition(
DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
bean.getPropertyValues().add("loadOnStartup", 1);
}
};
}
Reference:
how to configure 'dispatcherServlet' load on startup by spring boot?
Upate
Seems there is a more simple way, you can config it in application.properites
spring.mvc.servlet.load-on-startup=1

Resources