I made an app with JavaFX and it worked correctly when I build the project with the build button on IntelliJ IDE.
However it doesn't work when I run from jar file generated from gradle JavaFX project and the following error is shown on console.
$java -jar sample-menu-all.jar
java.io.FileNotFoundException: file:/Users/myuser/MyProjectRoot/build/libs/sample-menu-all.jar!/images/main_menu/icon.svg (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:220)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:158)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:113)
at java.base/java.io.FileReader.<init>(FileReader.java:58)
at presentation.utils.ImageUtil.loadSvgImage(ImageUtil.java:23)
at presentation.controller.MenuController.loadRegistrationButtonImage(MenuController.java:25)
at presentation.controller.MenuController.initialize(MenuController.java:20)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3253)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3210)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3179)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3152)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3144)
at presentation.navigator.VitalBitMenuNavigator.launchNewScene(VitalBitMenuNavigator.java:22)
at presentation.navigator.VitalBitMenuNavigator.launchMenuStage(VitalBitMenuNavigator.java:33)
at presentation.MainApp.start(MainApp.java:20)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:919)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
javafx.fxml.LoadException:
file:/Users/myuser/MyProjectRoot/build/libs/sample-menu-all.jar!/fxml/menu.fxml
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3253)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3210)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3179)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3152)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3144)
at presentation.navigator.VitalBitMenuNavigator.launchNewScene(VitalBitMenuNavigator.java:22)
at presentation.navigator.VitalBitMenuNavigator.launchMenuStage(VitalBitMenuNavigator.java:33)
at presentation.MainApp.start(MainApp.java:20)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:919)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Caused by: java.lang.NullPointerException
at javafx.swing/javafx.embed.swing.SwingFXUtils.toFXImage(SwingFXUtils.java:77)
at presentation.utils.ImageUtil.loadSvgImage(ImageUtil.java:30)
at presentation.controller.MenuController.loadRegistrationButtonImage(MenuController.java:25)
at presentation.controller.MenuController.initialize(MenuController.java:30)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
... 15 more
My directory structure is this
ProjectRootDir
|-- build
|-- libs
sample-menu-all.jar
|-- build.gradle
|-- src
|-- main
|-- java
|-- presentation
MainApp.java
|-- controller
|-- MenuController.java
|-- navigator
|-- MenuNavigator.java
|-- utils
|-- ImageUtile.java
|-- resources
|-- fxml
|-- menu.fxml
|-- properties
|-- string.properties
The gradle file, main.java and the class fxml is loaded are in the snnipet link.
build.gradle
buildscript {
dependencies {
classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.8.2'
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
}
repositories {
jcenter()
mavenLocal()
mavenCentral()
}
}
plugins {
id 'java'
}
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'javafx-gradle-plugin'
mainClassName = 'presentation.MainApp'
sourceCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
// Camera lib
compile 'com.github.sarxos:webcam-capture:0.3.12'
compile 'org.slf4j:slf4j-log4j12:1.7.21'
// RxJavaFX
implementation "io.reactivex.rxjava2:rxjava:2.2.2"
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
// Batik (for loading AVG)
compile group: 'org.apache.xmlgraphics', name: 'batik-transcoder', version: '1.10'
}
jfx {
mainClass = 'MainApp'
vendor = 'myVendor'
}
jar {
manifest {
attributes 'Main-Class': 'presentation.MainApp'
}
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
sourceSets {
main {
java {
srcDirs 'src/main/java'
}
resources {
srcDirs 'src/main/resources'
}
}
}
MainApp.java
package presentation;
import javafx.application.Application;
import javafx.stage.Stage;
import presentation.navigator.MenuNavigator;
public class MainApp extends Application {
public static Stage primaryStage;
private MenuNavigator navigator;
public MainApp() {
navigator = new MenuNavigator();
}
#Override
public void start(Stage primaryStage) throws Exception {
MainApp.primaryStage = primaryStage;
navigator.launchMenuStage(primaryStage);
}
public static void main(String[] args) {
launch(args);
}
}
MenuNavigator.java
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import presentation.utils.ResourceBundleUtf8Control;
import presentation.utils.config.Config;
import java.io.File;
import java.net.URL;
import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;
public class MenuNavigator {
private void launchNewScene(Stage stage, String $fxmlName) {
try {
URL location = getClass().getResource("/fxml/" + $fxmlName);
ResourceBundle resources = ResourceBundle.getBundle("properties.string", Locale.getDefault(), new ResourceBundleUtf8Control());
Parent root = FXMLLoader.load(location, resources);
Scene scene = new Scene(root, Config.loadDimen("dimension.app_screen_size.width"), Config.loadDimen("dimension.app_screen_size.height"));
stage.setScene(scene);
stage.setTitle(Config.loadString("string.title"));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void launchMenuStage(Stage stage) {
launchNewScene(stage, "menu.fxml");
}
}
MenuContoroller.java
package presentation.controller;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import presentation.MainApp;
import presentation.utils.FileUtil;
import presentation.utils.ImageUtil;
import java.net.URL;
import java.util.ResourceBundle;
public class MenuController extends BaseController implements Initializable {
public Button userRegistrationButton;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
this.loadRegistrationButtonImage();
}
private void loadRegistrationButtonImage() {
ImageView buttonImage = new ImageView();
ImageUtil.loadSvgImage(buttonImage, "/images/main_menu/icon.svg", 71, 94);
userRegistrationButton.setGraphic(buttonImage);
userRegistrationButton.setGraphicTextGap(37.5);
}
}
ImageUtile.java
package presentation.utils;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.net.URL;
public class ImageUtil {
public static void loadSvgImage(ImageView target, String resourcePath, int withd, int height) {
SvgTranscoder imageTranscoder = new SvgTranscoder();
imageTranscoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) withd);
imageTranscoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) height);
try {
URL imagePath = ImageUtil.class.getResource(resourcePath);
TranscoderInput input = new TranscoderInput(new FileReader(imagePath.getFile()));
imageTranscoder.transcode(input, null);
} catch (FileNotFoundException | TranscoderException e) {
e.printStackTrace();
}
BufferedImage bimage = imageTranscoder.getImage();
WritableImage wimage = SwingFXUtils.toFXImage(bimage, null);
target.setImage(wimage);
}
}
SvgTranscoder.java
package presentation.utils;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;
import java.awt.image.BufferedImage;
public class SvgTranscoder extends ImageTranscoder {
private BufferedImage image = null;
#Override
public BufferedImage createImage(int w, int h) {
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
return image;
}
#Override
public void writeImage(BufferedImage img, TranscoderOutput out) {
}
public BufferedImage getImage() {
return image;
}
}
The same code snippets are here too.
https://snippets.cacher.io/snippet/3dab5b901e6aa5e861e3
I unpacked the jar file and checked fxml directory and files are included.
This is the screenshot.
Unpacked jar files
I would really appreciate if someone advise me on this problem.
The problem is this:
new FileReader(imagePath.getFile())
Despite its name, the getFile() method of the URL class does not return a valid file name and does not convert a URL to a file. (The method was introduced in Java 1.0, over twenty years ago, back when most URLs did in fact represent physical files on either the same computer or a different computer.)
Even if it did, a .jar file is a single archive—entries inside it are not files themselves, just subsequences of bytes representing compressed data.
You must refer to a resource in a .jar entry as a resource URL or its equivalent stream. You must not attempt to convert it to a file.
Fortunately, you don’t need a file. You can pass the URL directly, as a String:
URL imagePath = ImageUtil.class.getResource(resourcePath);
TranscoderInput input = new TranscoderInput(imagePath.toString());
Related
I have a Spring Boot App with the following classes in the src/main/java/in/javacoder/overlayapp package
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.2'
id 'io.spring.dependency-management' version '1.1.0'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.13'
}
javafx {
version = "17"
modules = [ 'javafx.controls' ]
}
group = 'in.techpro424'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
CoordinateOverlayAppApplication.java
package in.techpro424.coordinateoverlayapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CoordinateOverlayAppApplication {
public static void main(String[] args) {
SpringApplication.run(CoordinateOverlayAppApplication.class, args);
}
}
CoordinateRestController.java
package in.techpro424.coordinateoverlayapp;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class CoordinateRestController {
public static double xCoord;
public static double yCoord;
public static double zCoord;
#PostMapping(value = "/coordinateOverlay")
public int receiveCoordinates(#RequestParam(name = "xCoordinate") Double xCoordinate, #RequestParam(name = "yCoordinate") Double yCoordinate, #RequestParam(name = "zCoordinate") Double zCoordinate) {
CoordinateRestController.xCoord = xCoordinate;
System.out.println(CoordinateRestController.xCoord);
CoordinateRestController.yCoord = yCoordinate;
System.out.println(CoordinateRestController.yCoord);
CoordinateRestController.zCoord = zCoordinate;
System.out.println(CoordinateRestController.zCoord);
javafx.application.Application.launch(RenderCoordinateOverlay.class);
return 1;
}
}
RenderCoordinateOverlay.java
package in.techpro424.coordinateoverlayapp;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class RenderCoordinateOverlay extends Application {
double radius = 50;
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Text coordinates = new Text();
coordinates.setText("X:" + CoordinateRestController.xCoord + ", Y:" + CoordinateRestController.yCoord + ", Z:" + CoordinateRestController.zCoord);
root.getChildren().add(coordinates);
Scene scene = new Scene(root, Color.TRANSPARENT);
scene.getRoot().setStyle("-fx-background-color: transparent");
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setAlwaysOnTop(true);
}
public static void main(String[] args) {
launch(args);
}
}
I want to render this overlay on the screen whenever I receive the POST request with the specified params
I tried using javafx.application.Application.launch(RenderCoordinateOverlay.class); in the receiveCoordinates() function
I expected the overlay to render the text the moment I sent the POST request
However, when I sent the POST request, only a completely transparent window was rendered with this error in the console:
2023-01-27T15:01:27.384+05:30 WARN 13060 --- [JavaFX-Launcher] javafx: Unsupported JavaFX configuration: classes were loaded from 'unnamed module #1ec4c0e8'
The SpringBoot application is running on my PC with a display and I expect the UI to be displayed on the PC.
I use Postman to send the post.
I am trying to build a jar with the following build.gradle:
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
}
application {
mainClass.set("edu.hm.dako.auditLogServer.AdminGuiStarter")
}
jar.enabled = true
javafx {
version = "18"
modules = ['javafx.controls', 'javafx.fxml']
}
sourceSets {
main {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.fxml"]
}
}
}
dependencies {
implementation project(':common')
implementation project(':communication')
implementation 'org.openjfx:javafx:18'
implementation group: 'org.apache.commons', name: 'commons-configuration2', version: '2.8.0'
implementation group: 'commons-beanutils', name: 'commons-beanutils', version: '1.9.4'
}
repositories {
mavenCentral()
}
jar {
manifest {
attributes "Main-Class": "edu.hm.dako.auditLogServer.AdminGuiStarter"
}
archiveBaseName = 'AdminGradle'
archiveVersion = '0.1.0'
}
The Main class of the project is following:
package edu.hm.dako.auditLogServer;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class AdminGuiStarter extends Application{
#Override
public void start(Stage stage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("AdminGui.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
System.out.println(e);
}
}
// bitte über gradle starten, da sonst JavaFx Runtime components fehlen
public static void main(String[] args) {
launch();
}
}
When I then try to execute the jar, I get this error: java.lang.NoClassDefFoundError: javafx/application/Application
How can I fix this so that the jar will execute successful? When I run the Application via Gradle run, everything works fine.
I start learning Spring and in the tutorial from which I learn the lecturer uses the method: startAndAwait, which was in the reactor.ipc.netty.http.server.HttpServer package. Now there is no method, and the package is reactor.netty.http.server.HttpServer.
I would like to learn a solution based on the latest package, therefore my question is what will be the current equivalent of the following code:
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.ipc.netty.http.server.HttpServer;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args)
{
RouterFunction route = route( GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServer server = HttpServer.create("localhost",8080);
server.startAndAwait(new ReactorHttpHandler(httpHandler));
}
}
I was looking for a solution, but my knowledge is so low that I can not cope alone with this problem. So far I wrote I changed the code to the place "server.startAndAwait" still can not replace this method:
package pl.javasurvival.helloServer;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args)
{
RouterFunction route = route( GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServer server = HttpServer
.create()
.host("localhost")
.port(8080);
//what is a new method which is equals to startAndAwait
}
}
PS: I forgot to add that I use gradle. This is the build.gradle file:
plugins {
id 'org.springframework.boot' version '2.2.0.M4'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'pl.javasurvival'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux:2.2.0.M4'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
exclude group: 'junit', module: 'junit'
}
testImplementation 'io.projectreactor:reactor-test'
}
test {
useJUnitPlatform()
}
it has been a while, but I've found this question 1 hour ago and now I have solution, so it could be helpful for others.
Without importing old version of reactor.netty, you could try this (scanner is added only for waiting for action)
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import java.util.Scanner;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args) {
RouterFunction route = route(GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
var httpHandler = RouterFunctions.toHttpHandler(route);
var adapter = new ReactorHttpHandlerAdapter(httpHandler);
var server = HttpServer.create().host("localhost").port(8080).handle(adapter).bindNow();
System.out.println("press enter");
Scanner sc = new Scanner(System.in);
sc.next();
server.disposeNow();
}
}
You can use the method block, as in:
DisposableServer server =
HttpServer.create()
.bindNow();
server.onDispose()
.block();
Read more in the Reactor Netty docs.
I have a java web app, which I am using cloud9 for, and I have set up Apache freemarker as a templating engine. To import the package I used gradle, but when I run gradle build, I get exceptions due to references to the freemarker package in my code. When I comment out all uses of freemarker aside from the import statement, my gradle will build my code, but it will throw errors when I run it (freemarker package does not exist). How can I fix this?
App.java
import freemarker.template.*;
import com.sun.net.httpserver.HttpServer;
import java.net.*;
import java.util.*;
public class App{
public static Configuration cfg = new Configuration(Configuration.VERSION_2_3_27);
int port;
public static void main(String[] args){
App app = new App(8081);
try{
app.init();
app.templateConfig();
}catch(Exception e){
System.out.println(e);
}
}
public App(int port){
this.port = port;
}
public void init() throws Exception{
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
System.out.println("server started at " + port);
server.createContext("/", new HomeController.Index());
server.createContext("/echoHeader", new HomeController.EchoHeaderHandler());
server.createContext("/echoGet", new HomeController.EchoGetHandler());
server.createContext("/echoPost", new HomeController.EchoPostHandler());
server.setExecutor(null);
server.start();
}
public void templateConfig() throws Exception{
cfg.setDirectoryForTemplateLoading(new File("../templates"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHanlder.HTML_DEBUG_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
}
}
HomeController.java
import freemarker.template.*;
import com.sun.net.httpserver.*;
import java.net.*;
import java.io.*;
import java.util.*;
public class HomeController{
public static class Index implements HttpHandler{
public void handle(HttpExchange exchange) throws IOException{
//String response = "<h1>Server start success if you see this message</h1><h1>Port: " + 8081 + "</h1>";
exchange.sendResponseHeaders(200, response.length());
OutputStream os = exchange.getResponseBody();
//os.write(response.getBytes());
Map<String, Object> root = new HashMap<>();
root.put("port", 3000);
Template home = App.cfg.getTemplate("home.ftlh");
home.process(root, os);
os.close();
}
}
public static class EchoHeaderHandler implements HttpHandler{
public void handle(HttpExchange exchange){
}
}
public static class EchoGetHandler implements HttpHandler{
public void handle(HttpExchange exchange){
}
}
public static class EchoPostHandler implements HttpHandler{
public void handle(HttpExchange exchange){
}
}
}
build.gradle
repositories {
mavenCentral()
}
apply plugin: "java"
dependencies {
compile "org.freemarker:freemarker:2.3.28"
}
sourceSets {
main.java.srcDir "src/main"
}
jar {
from configurations.compile.collect { zipTree it }
manifest.attributes "Main-Class":"com.isaackrementsov.app.App"
}
My directory structure
workspace
build
classes
java
main
//Source code compiles here
libs
tmp
compileJava
jar
src
main
com
isaackrementsov
app
//Source code here
My whole project is here: Cloud9 Project
I have gone thru the documentation of Firestore: https://firebase.google.com/docs/firestore/query-data/listen?authuser=0
But while using same code, i am not able to resolve symbols such as DocumentChange, EventListener.
Similarly, I am not able to resolve methods such as getDocumentChanges, getDocument, addSnapshotListener.
I have already imported 'com.google.firebase:firebase-admin:5.8.0'.
build.gradle file
group 'firestore'
version '1.0-SNAPSHOT'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
dependencies {
compile 'com.google.firebase:firebase-admin:5.8.0'
}
Here is the code, I am trying:
package firestore;
import com.google.api.core.SettableApiFuture;
import com.google.firestore.v1beta1.DocumentChange;
import com.google.cloud.firestore.DocumentChange;
import com.google.cloud.firestore.DocumentChange.Type;
import com.google.cloud.firestore.EventListener;
import com.google.cloud.firestore.ListenerRegistration;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreException;
import com.google.cloud.firestore.Query;
import com.google.cloud.firestore.QuerySnapshot;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import static com.google.api.ChangeType.ADDED;
import static com.google.api.ChangeType.MODIFIED;
import static com.google.api.ChangeType.REMOVED;
/**
* Snippets to demonstrate Firestore 'listen' operations.
*/
#SuppressWarnings("Convert2Lambda")
public class FirestoreChange {
private static final long TIMEOUT_SECONDS = 5;
private final Firestore db;
FirestoreChange(Firestore db) {
this.db = db;
}
/**
* Listen to a query, returning the list of DocumentChange events in the first snapshot.
*/
List<DocumentChange> listenForChanges() throws Exception {
SettableApiFuture<List<DocumentChange>> future = SettableApiFuture.create();
// [START listen_for_changes]
db.collection("cities")
.whereEqualTo("state", "CA")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot snapshots,
#Nullable FirestoreException e) {
if (e != null) {
System.err.println("Listen failed: " + e);
return;
}
for (DocumentChange dc : snapshots.getDocumentChanges()) {
switch (dc.getType()) {
case ADDED:
System.out.println("New city: " + dc.getDocument().getData());
break;
case MODIFIED:
System.out.println("Modified city: " + dc.getDocument().getData());
break;
case REMOVED:
System.out.println("Removed city: " + dc.getDocument().getData());
break;
default:
break;
}
}
// [START_EXCLUDE silent]
if (!future.isDone()) {
future.set(snapshots.getDocumentChanges());
}
// [END_EXCLUDE]
}
});
// [END listen_for_changes]
return future.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
}
This is happening because you didn't add Cloud Firestore dependencies in build.gradle file at all. Adding firebase-admin is not enought to make Firestore work. So to solve this, just add this line of code:
compile 'com.google.firebase:firebase-firestore:11.8.0'
Right after the firebase-admin dependencies. Sync your project and try again.