I want to create a custom control in an executable jar file and then use in Gluon Scene Builder 11.00. I need to know how to do this. I tried several forms but my controls not appear when import jar in Scene Builder. I am using IntelliJ Community Edition 2019.2 and Gluon Scene Builder 11.00 and Java 12.0.2. Anyone please that could help me with a little example?
Maven Project.
custom_control.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="51.0" prefWidth="138.0" type="VBox" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField fx:id="textField" />
<Button mnemonicParsing="false" onAction="#doSomething" prefHeight="25.0" prefWidth="142.0" text="Clck Me" />
</children>
</fx:root>
CustomControl.java
package customcontrolexample;
import java.io.IOException;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
public class CustomControl extends VBox {
#FXML private TextField textField;
public CustomControl() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"custom_control.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public String getText() {
return textProperty().get();
}
public void setText(String value) {
textProperty().set(value);
}
public StringProperty textProperty() {
return textField.textProperty();
}
#FXML
protected void doSomething() {
System.out.println("The button was clicked!");
}
}
CustomControlExample.java
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class CustomControlExample extends Application {
private static Scene scene;
#Override
public void start(Stage stage) throws IOException {
CustomControl customControl = new CustomControl();
customControl.setText("Hello!");
stage.setScene(new Scene(customControl));
stage.setTitle("Custom Control");
stage.setWidth(300);
stage.setHeight(200);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>customcontrol</groupId>
<artifactId>CustomControlExample</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>12.0.2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>12.0.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.3</version>
<configuration>
<mainClass>CustomControlExample</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>CustomControlExample</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
There are a few things to consider when you want to create a custom control that can be imported with Scene Builder.
What qualifies as custom control
There is no documentation about this, but you can have a look at the current source code in Scene Builder that explores all the classes in a jar, and finds valid classes as custom controls:
Classname not starting with java., javax., javafx.,
com.oracle.javafx.scenebuilder., com.javafx., com.gluonhq.
Concrete class (not abstract)
Assignable from Node. This is quite important: the class should be a subclass of a JavaFX node, like a container (i.e. extends from VBox) or a built-in node (i.e. extends from Button).
For all the classes found, then an FXML is built with something like:
<?import your.class.fullname?>
<your.class.simplename />
If that FXML can be loaded by the FXMLLoader, then it is a custom control.
Otherwise it is discarded.
Type of custom control
There are several approaches on how to build a custom control, but if you are going to use FXML this old tutorial gives some important clarification on how to use fx:root and how to define the controller, like:
public class CustomControl extends VBox {
public CustomControl() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"custom_control.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
...
}
Java 11 level
Finally, since Scene Builder 11 runs on Java 11, the jar has to be compiled with support for Java 11.
Using Maven:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
Before going to Scene Builder, you can try your custom control in a demo project. This will help you find and solve possible issues in advance.
Scene Builder 11
Once you have built the control, you can open Scene Builder 11 and import it following the documentation.
Basically, using the option Add Library/FXML from file system and browsing your file system to locate the jar.
Note: there is a merged PR that will allow using the build/target directory of a project, instead of requiring a jar.
In case of the posted custom control, you should get this:
If the view doesn't show your control, there is an issue that you have to solve first.
Note: there is a pending PR that will provide more information when the process fail.
Related
Hi if I use a custom component in SceneBuilder that uses an external library in the constructor or the initialize method, I get an java.lang.ClassNotFoundException exception when try to open the FXML with JavaFX SceneBuilder 8.5.0.
I followed the instructions from here: https://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm.
The custom component is part of my Eclipse project. I don't want to export it as an external jar file.
When I run this application in Eclipse everything works fine. The external library "FontAwesomeIcon" is part of my build path in Eclipse.
When I try to open the FXML of the custom component with SceneBuilder (with the Terminal to get debug logs), I get the following output and no file is loaded:
/Applications/SceneBuilder.app/Contents/MacOS/SceneBuilder /Users/phillip/MEGA/Eclipse/JTunes/src/test/TestWindow.fxml
Jan 09, 2021 6:31:44 PM com.oracle.javafx.scenebuilder.app.SceneBuilderApp logTimestamp
INFORMATION: JavaFX Scene Builder started
TestComponent()
TestComponent: Init
Jan 09, 2021 6:31:45 PM com.oracle.javafx.scenebuilder.app.SceneBuilderApp$SceneBuilderUncaughtExceptionHandler uncaughtException
SCHWERWIEGEND: An exception was thrown:
java.lang.NoClassDefFoundError: de/jensd/fx/glyphs/fontawesome/FontAwesomeIcon
at test.TestComponent.initialize(TestComponent.java:28)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
at test.TestComponent.<init>(TestComponent.java:22)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1009)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:746)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
at com.oracle.javafx.scenebuilder.kit.fxom.FXOMLoader.load(FXOMLoader.java:93)
at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.<init>(FXOMDocument.java:89)
at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.<init>(FXOMDocument.java:106)
at com.oracle.javafx.scenebuilder.kit.editor.EditorController.updateFxomDocument(EditorController.java:2540)
at com.oracle.javafx.scenebuilder.kit.editor.EditorController.setFxmlTextAndLocation(EditorController.java:761)
at com.oracle.javafx.scenebuilder.app.DocumentWindowController.loadFromFile(DocumentWindowController.java:385)
at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.performOpenFiles(SceneBuilderApp.java:672)
at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.access$100(SceneBuilderApp.java:98)
at com.oracle.javafx.scenebuilder.app.SceneBuilderApp$1.invalidated(SceneBuilderApp.java:524)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:72)
at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
at com.oracle.javafx.scenebuilder.kit.library.user.UserLibrary.lambda$updateFirstExplorationCompleted$6(UserLibrary.java:352)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
Caused by: java.lang.ClassNotFoundException: de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 36 more
Jan 09, 2021 6:31:46 PM com.oracle.javafx.scenebuilder.app.SceneBuilderApp logTimestamp
INFORMATION: JavaFX Scene Builder stopped
Can someone explain the whole thing to me? I don't understand why SceneBuilder has to call the constructor or the initialize method.
If I didn't understand the use of custom components in JavaFX and SceneBuilder correctly, what is the right way to do this?
Thanks for your help and greetings from Germany.
Following the content of my files...
Main class (Initializes the JavaFX application and opens the main window):
package test;
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage = new TestWindow();
primaryStage.show();
}
}
Test window class (Loads the test window FXML). This window uses the custom component:
package test;
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TestWindow extends Stage {
public TestWindow() throws IOException {
System.out.println("TestWindow()");
FXMLLoader loader = new FXMLLoader();
loader.setController(this);
loader.setLocation(this.getClass().getResource("TestWindow.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
this.setScene(scene);
}
}
FXML of test window:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import test.TestComponent?>
<VBox alignment="CENTER" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TestComponent />
</children>
</VBox>
Custom component class (Uses an external library "FontAwesomeIcon" that crashes SceneBuilder - corresponding line is bold):
package test;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.layout.VBox;
public class TestComponent extends VBox implements Initializable {
public TestComponent() throws IOException {
System.out.println("TestComponent()");
FXMLLoader loader = new FXMLLoader();
loader.setController(this);
loader.setRoot(this);
loader.setLocation(this.getClass().getResource("TestComponent.fxml"));
loader.load();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("TestComponent: Init");
System.out.println("TestComponent: "+FontAwesomeIcon.ADJUST);
}
#FXML
private void click() {
System.out.println("Click");
}
}
FXML of custom component:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<fx:root alignment="CENTER" type="VBox" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="TestComponent" />
<Button onMouseClicked="#click" text="Button" />
</children>
</fx:root>
Update:
When I add the .jar file for the class "de/jensd/fx/glyphs/fontawesome/FontAwesomeIcon" to the "app.classpath" option in the SceneBuilder configuration file, the fxml opens without any exception.
Do I really need to add every external library to this setting?
I spent a lot of time to debug this problem, but I could not find a solution. So then I used a workaround but I want to share the problem in order to help someone in the same situation.
The application, in a nutshell, is a TeamCity plugin, which communicates with nexus repository.
pom.xml:
<?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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>some-plugin</artifactId>
<groupId>com.something</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>some-plugin-server</artifactId>
<packaging>jar</packaging>
<properties>
<jaxb.version>2.3.0</jaxb.version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.teamcity</groupId>
<artifactId>server-api</artifactId>
<version>${teamcity-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.teamcity</groupId>
<artifactId>server-web-api</artifactId>
<version>${teamcity-version}</version>
<type>war</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.teamcity</groupId>
<artifactId>tests-support</artifactId>
<version>${teamcity-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
There is mentiond parent but it contains nothing more than repositories and pluginRepositories settings.
Annotations above my java classes:
#XmlRootElement(name = "versioning")
#XmlAccessorType(XmlAccessType.FIELD)
public class Versioning implements Serializable {
private static final long serialVersionUID = 2L;
private String latest;
private String release;
#XmlElementWrapper(name="versions")
#XmlElement(name = "version")
private List<String> versions;
public String getLatest() {
return latest;
}
public void setLatest(String latest) {
this.latest = latest;
}
public String getRelease() {
return release;
}
public void setRelease(String release) {
this.release = release;
}
public List<String> getVersions() {
return versions;
}
public void setVersions(List<String> versions) {
this.versions = versions;
}
}
#XmlRootElement(name = "metadata")
#XmlAccessorType(XmlAccessType.FIELD)
public class MetaData implements Serializable {
private static final long serialVersionUID = 1L;
#XmlElement(name = "versioning")
private Versioning versioning;
public Versioning getVersioning() {
return versioning;
}
public void setVersioning(Versioning versioning) {
this.versioning = versioning;
}
}
The classes represents metadata.xml from nexus. From pom.xml there is no clear that teamcity dependencies adding spring 4 into my project:
Spring configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-autowire="constructor">
<bean id="versionService" class="com.aliter.teamcity.service.impl.VersionServiceImpl" autowire="byName"/>
<bean id="appController" class="com.aliter.teamcity.AppController"/>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>
</beans>
In the VersionServiceImpl.class, there is a method sending request into nexus:
private MetaData getMetaData(String url) {
HttpEntity<String> request = new HttpEntity<>(getAuthorization());
try {
ResponseEntity<MetaData> metaDataResponseEntity = restTemplate.exchange(url, HttpMethod.GET, request, MetaData.class);
return metaDataResponseEntity.getBody();
} catch (RestClientException e) {
LOGGER.error("Metadata xml cannot be obtained.", e);
return null;
}
}
private HttpHeaders getAuthorization() {
String plainCreds = "username:password";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_XHTML_XML, MediaType.TEXT_HTML));
headers.add("Authorization", "Basic " + base64Creds);
return headers;
}
I got the exception: RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.aliter.teamcity.model.MetaData] and content type [application/xml]
RestTemplate explicitly by this: private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", RestTemplate.class.getClassLoader()); registers Jaxb2RootElementHttpMessageConverter, it was there I checked that. I did debug and stopped when spring Http response handler trying to recognize through Jaxb2RootElementHttpMessageConverter JAXB annotations above my classes and from method:
#Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
canRead(mediaType);
}
It returns that annotations are not present above the classes, but they are even there. I used JDK 8.
I am using Glassfish 5.0 with a Java Web App built in Maven framework. I have set up the Connection Pool and it is connected when you ping it.
I have placed the persistent.xml file in
src/main/java/META-INF
with the config:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="ramsoPU" transaction-type="JTA">
<jta-data-source>jdbc/ramsovarvet</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
</properties>
</persistence-unit>
</persistence>
However, when trying to instantiate the EntityManager I get the error message 'Caused by: java.lang.IllegalStateException: Unable to retrieve EntityManagerFactory for unitName null'
I have checked that the peristent.xml is in the classpath in the war file. it is in:
WEB-INF/classes/META-INF/persistence.xml
The JNDI name is correct, as I set it up in the server context.
Below is the code where I instantiate the EM with the persistent unit:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package uk.ac.city.douglas.varv.Job.dao;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import uk.ac.city.douglas.varv.Account.domain.Customer;
import uk.ac.city.douglas.varv.Job.domain.Boat;
import uk.ac.city.douglas.varv.Job.domain.BoatVariant;
import uk.ac.city.douglas.varv.Job.domain.BoatVariantEngine;
import uk.ac.city.douglas.varv.Job.domain.Engine;
import uk.ac.city.douglas.varv.Job.domain.Storage;
/**
*
* #author douglaslandvik
*/
#Stateless
public class VarvRepositoryJPQL implements VarvRepository {
#PersistenceContext(unitName="ramsoPU")
private EntityManager em;
#Override
public List<Customer> getAllCustomers(){
TypedQuery query = em.createQuery("SELECT c FROM Customer AS c",Customer.class);
return query.getResultList();
}
#Override
public List<Boat> getAllBoats() {
TypedQuery query = em.createQuery("SELECT b FROM Boat AS b ORDER by b.brand ASC",Boat.class);
return query.getResultList();
}
#Override
public void addEmployee() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void saveBoat(Boat boat) {
em.persist(boat);
}
#Override
public void saveCustomer(Customer customer) {
em.persist(customer);
}
#Override
public void eraseCustomerById(int id) {
Customer customer = em.find(Customer.class, id);
em.remove(customer);
}
#Override
public List<Storage> getAllStorages() {
TypedQuery query = em.createQuery("SELECT s FROM Storage AS s",Storage.class);
return query.getResultList();
}
#Override
public List<Engine> getAllEngines() {
TypedQuery query = em.createQuery("SELECT e FROM Engine AS e",Engine.class);
return query.getResultList();
}
#Override
public List<BoatVariant> getAllBoatVariants() {
TypedQuery query = em.createQuery("SELECT b FROM BoatVariant AS b",BoatVariant.class);
return query.getResultList();
}
#Override
public void saveBoatVariant(BoatVariant boatVariant) {
em.persist(boatVariant);
}
#Override
public List<Boat> getAllBoatsByBrand(String brand) {
TypedQuery query = em.createQuery("SELECT b FROM Boat AS b WHERE b.brand LIKE :brand ORDER BY b.brand", Boat.class);
query.setParameter("brand", brand+"%");
return query.getResultList();
}
#Override
public List<Boat> getAllBoatsByModel(String model) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public List<Boat> getAllBoatsById(int id) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public List<String> getAllBoatBrands() {
TypedQuery query = em.createQuery("SELECT DISTINCT b.brand FROM Boat AS b", String.class);
return query.getResultList();
}
#Override
public Boat findBoatById(int id) {
return em.find(Boat.class, id);
}
#Override
public Customer findCustomerById(int id) {
return em.find(Customer.class, id);
}
#Override
public List<Engine> findEnginesByBrand(String brand) {
TypedQuery query = em.createQuery("SELECT e FROM Engine AS e WHERE e.brand LIKE :brand ORDER BY e.brand", Engine.class);
query.setParameter("brand", brand+"%");
return query.getResultList();
}
#Override
public void addEngine(Engine engine) {
em.persist(engine);
}
#Override
public Engine findEngineById(int id) {
return em.find(Engine.class, id);
}
#Override
public void removeEngineById(int id) {
Engine engine = em.find(Engine.class, id);
em.remove(engine);
}
#Override
public List<BoatVariant> findAllBoatVariantByCustomerId(int customerId) {
TypedQuery query = em.createQuery("SELECT bv FROM BoatVariant AS bv WHERE bv.customerId = :customerId ", BoatVariant.class);
query.setParameter("customerId", customerId);
return query.getResultList();
}
//nya jävlar
#Override
public void addBoatVariantEngine(BoatVariantEngine boatVariantEngine) {
em.persist(boatVariantEngine);
}
#Override
public void removeBoatVariantEngineById(BoatVariantEngine boatVariantEngine) {
em.remove(boatVariantEngine);
}
#Override
public List<BoatVariantEngine> findBoatVariantEngineById(int boatId, int customerId, int engineId) {
TypedQuery query = em.createQuery("SELECT bve FROM BoatVariantEngine AS bve WHERE bve.customerId = :customerId AND bve.boatId = :boatId AND bve.engineId = :engineId ", BoatVariantEngine.class);
query.setParameter("customerId", customerId);
query.setParameter("boatId", boatId);
query.setParameter("engineId", engineId);
return query.getResultList();
}
#Override
public BoatVariant findAllBoatVariantByCustomerIdAndBoatId(int customerId, int boatId) {
TypedQuery query = em.createQuery("SELECT bv FROM BoatVariant AS bv WHERE bve.customerId = :customerId AND bve.boatId = :boatId", BoatVariant.class);
query.setParameter("customerId", customerId);
query.setParameter("boatId", boatId);
return (BoatVariant) query.getSingleResult();
}
#Override
public void removeBoatVariant(BoatVariant boatVariant) {
em.remove(boatVariant);
}
}
The pom file is below:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>uk.ac.city.douglas</groupId>
<artifactId>varv</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<name>varv</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
<version>2.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.asayama.gwt.jquery</groupId>
<artifactId>gwt-jquery</artifactId>
<version>0.1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.bluecatcode.mockito</groupId>
<artifactId>mockito-1.10.19-extended</artifactId>
<version>1.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>varv</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>varv</warName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>7.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The name of the persistence unit file must be persistence.xml but in your case the name of the file is persistent.xml, that's why the container can't detect the persistence unit name.
So change the persistence file name to persistence.xml. Also don't forget to call the service class VarvRepositoryJPQL using #EJB for example:
#EJB
VarvRepositoryJPQL varvRepository;
and then call it.
Validation of RequestParam using custom validation annotation #ValidCode doesn't work. But If use #Pattern instead it starts working. What am I doing wrong, please?
The controller:
#Validated
#RestController
public class MyEndpoint {
#RequestMapping(path = "/test", method = GET)
public MyResponse findItems(#ValidCode #RequestParam("code") String code) {
return new MyResponse("A001");
}
}
My validation annotation:
#Retention(RUNTIME)
#Target({FIELD, PARAMETER})
#Pattern(regexp = "^[A-Z0-9]{4}?$")
public #interface ValidCode {
String message() default "{ValidCode.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Web MVC config:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}
pom.xml:
<?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 http://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>1.3.1.RELEASE</version>
<relativePath></relativePath>
</parent>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
...
</dependencies>
</project>
BUT if I change controller method following way validation starts working:
#RequestMapping(path = "/test", method = GET)
public MyResponse findItems(#Pattern(regexp="^[A-Z0-9]{2}?$") #RequestParam("code") String code) {
return new MyResponse("A001");
}
Many thanks in advance.
i am new to Spring MVC, i have created spring 3.2 project using maven in eclipse. i am implementing AbstractAnnotationConfigDispatcherServletInitializer class for java based configuration.
i have following plugins and dependencies in pom.xml
<build>
<plugins>
<!--source level should be 1.6 (which is not Maven default) for java EE
6 projects, so let's change it -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<!-- When using xml-less approach, you need to disable Maven's warning
about missing web.xml -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--We need servlet API for compiling the classes. Not needed in runtime
-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--adding spring mvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<!-- Add Taglib support -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
Initializer class is as......
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebappConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
WebappConfig class is as......
#Configuration
#ComponentScan(basePackages={"com.sandip.controllers"})
#EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter{
//add view Resolver, Tell SpingMVC where to find view scripts
#Bean
public InternalResourceViewResolver setupViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
and finally i have a HomeController as..........
#Controller
public class HomeContoller {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home() {
return "home";
}
}
when i run this my project with jetty after maven build it display the following output in browser.....
springZeroXml is my project name there is no errro in console, please help ..........
I did lot of googleing and find out i need to override the addViewControllers method of WebMvcConfigurerAdapter class in WebAppConfig. and code is..........
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}