I have a problem with my injection, it's the first time I try it. I'm working with Wildfly and Java EE 7. I've got a NullPointerException when trying to access Authenticator instance in LoginController.
I use maven, my beans.xml is found under src/main/webapp/META-INF but I'v tried to put it in src/main/webapp/WEB-INF/classes without success.
Here is my code :
The class to inject :
#Stateless
public class Authenticator {
#Inject
HashGenerator hashGenerator;
#Inject
UserPersistance userPersistance;
public boolean authenticate(final String username, final String password) {
User user = userPersistance.getUser(username);
String salt = user.getSalt();
String hash = hashGenerator.hash(password, salt);
return user.getPassword().equals(hash);
}
}
The controller which throw NullPointerException :
#Stateless
public class LoginController {
#Inject
Authenticator authenticator;
public void login(String username, String password) {
if (authenticator.authenticate(username, password)) {
UI ui = UI.getCurrent();
ui.getSession().setAttribute(SessionAttribute.USER.getAttributeName(), username);
ui.getNavigator().navigateTo(MainView.getName());
}
}
}
And my beans.xml (Under src/main/webapp/META-INF)
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
What did I do wrong?
UPDATE
Sorry, I previously miswritten the folders name of beans.xml.
So, just to be clear, maven generate a WAR archive, and I've previously tried to put beans.xml under META-INF , WEB-INF and WEB-INF/classes. None of those folder seems to make it work. I've checked (tried and it works) a quickstart project from JBoss AS 7, and they put beans.xml under WEB-INF. I've done the same.
I think that maybe it comes from my Maven configuration. Here it is :
<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>be.normegil</groupId>
<artifactId>datamanager</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>datamanager</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
<failOnMissingWebXml>false</failOnMissingWebXml>
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss</maven.build.timestamp.format>
<vaadin.version>7.1.9</vaadin.version>
<vaadin.plugin.version>${vaadin.version}</vaadin.plugin.version>
</properties>
<pluginRepositories>
<pluginRepository>
<id>vaadin-snapshots</id>
<url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>3.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>${vaadin.version}</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-client-compiled</artifactId>
<version>${vaadin.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-themes</artifactId>
<version>${vaadin.version}</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-cdi</artifactId>
<version>1.0.0.alpha1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.7.1.1</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>1.0.0.Beta1</version>
</plugin>
</plugins>
</build>
</project>
So, I was able to fix my problem, here is what I've done :
Maven dependencies
I was assuming that javax:javaee-api was enough to use the functionnalities of Java EE 7. I've added dependencies to javax.enterprise:cdi-api, javax.inject:javax.inject and javax.annotation:javax.annotation-api
beans.xml
It's only one big project build into a war archive. I've put my beans.xml under src/main/webapp/WEB-INF (Is it necessary to have it at all with Wildfly ? Don't know)
Vaadin CDIUI
That's what solved my issue. I've tried to use Vaadin CDIUI without success. Vaadin was actually initializing my UI class with a new operation. Since it was not managed by the container, every Injection points didn't work (I've first fix it by doing new operations on my views and controllers, falling on the problem I've described)
I've refactored everything so injection is used in the views and controllers, and I've added #CDIUI to my Vaadin UI. Last, I've also added a new parameter to my servlet configuration (UIProvider) for this result :
#Theme("chameleon-green")
#Title("Data Manager")
#CDIUI("")
public class DataManagerUI extends UI {
#WebServlet(value = "/*",
asyncSupported = true,
initParams = {#WebInitParam(
name = "session-timeout",
value = "60"
),#WebInitParam(
name = "UIProvider",
value = "com.vaadin.cdi.CDIUIProvider"
)}
)
#VaadinServletConfiguration(productionMode = false,
ui = DataManagerUI.class,
closeIdleSessions = true
)
public static class Servlet extends VaadinServlet {
}
[...]
}
When normally instantiated with new operation from Vaadin framework, the UI class should be given by the UIProvider when using Injection.
Thanks for the help !
Related
i test i18n in gluon with its default project : gluon mobile single view . i add a print line to get : Locale.getdefault() . but is in english en_US and the device is in spanish . i have another large project with bundles and i had the same issue . i put the default project in this question 'cause i found better to show just small portion of code and replicate it .
the code
package com.local;
import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.control.Icon;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import java.util.Locale;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
public class BasicView extends View {
public BasicView() {
Label label = new Label("Hello JavaFX World!");
Button button = new Button("Change the World!");
button.setGraphic(new Icon(MaterialDesignIcon.LANGUAGE));
button.setOnAction(e -> {label.setText("Hello JavaFX Universe!");
// i add this line to default : gluon mobile single view
System.out.println(Locale.getDefault());});
VBox controls = new VBox(15.0, label, button);
controls.setAlignment(Pos.CENTER);
setCenter(controls);
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
appBar.setTitleText("Basic View");
appBar.getActionItems().add(MaterialDesignIcon.SEARCH.button(e -> System.out.println("Search")));
}
}
and i get this from console after install .apk on a real device
[vie. mar. 26 17:44:13 CLST 2021][INFO] [SUB] D/GraalCompiled(13989): en_US
pom file :
` <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>com.local</groupId>
<artifactId>local</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>>local</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>11</maven.compiler.release>
<javafx.version>16</javafx.version>
<attach.version>4.0.11</attach.version>
<client.plugin.version>0.1.38</client.plugin.version>
<javafx.plugin.version>0.0.5</javafx.plugin.version>
<mainClassName>com.local.Local</mainClassName>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq</groupId>
<artifactId>charm-glisten</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>${attach.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>lifecycle</artifactId>
<version>${attach.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>statusbar</artifactId>
<version>${attach.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>storage</artifactId>
<version>${attach.version}</version>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>util</artifactId>
<version>${attach.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>Gluon</id>
<url>https://nexus.gluonhq.com/nexus/content/repositories/releases</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>${javafx.plugin.version}</version>
<configuration>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>client-maven-plugin</artifactId>
<version>${client.plugin.version}</version>
<configuration>
<target>${client.target}</target>
<attachList>
<list>display</list>
<list>lifecycle</list>
<list>statusbar</list>
<list>storage</list>
</attachList>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>desktop</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<client.target>host</client.target>
</properties>
<dependencies>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>display</artifactId>
<version>${attach.version}</version>
<classifier>desktop</classifier>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>lifecycle</artifactId>
<version>${attach.version}</version>
<classifier>desktop</classifier>
</dependency>
<dependency>
<groupId>com.gluonhq.attach</groupId>
<artifactId>storage</artifactId>
<version>${attach.version}</version>
<classifier>desktop</classifier>
</dependency>
</dependencies>
</profile>
<profile>
<id>ios</id>
<properties>
<client.target>ios</client.target>
</properties>
</profile>
<profile>
<id>android</id>
<properties>
<client.target>android</client.target>
</properties>
</profile>
</profiles>
`
The problem you are facing is that the locale used to build the native image (usually the default locale on your machine, unless set otherwise) is the one that will be used on runtime, no matter what locale is set.
There is an open issue in GraalVM about this. There is no definitive fix for this yet, but it is expected to be available from GraalVM 21.1 (in just a couple of weeks).
For now, a workaround is to set the target's locale in the Client plugin configuration, like:
<nativeImageArgs>
<arg>-Duser.language=es</arg>
<arg>-Duser.country=ES</arg>
</nativeImageArgs>
and then run again
mvn -Pandroid client:build client:package
The generated APK will use the es_ES resource bundles.
Of course, this means that you would have to build a different image/APK for every language you support, which is really inconvenient.
I have my mail handler plugin which works fine in Jira 7.13.18, but when I try to start Jira 8.13.2 with that, plugin doesn't start. The reason is:
'Extended Mail Handler' failed to load.
Error creating bean with name 'sendMessageService': Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.atlassian.velocity.VelocityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport(value="")}
No qualifying bean of type 'com.atlassian.velocity.VelocityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport(value="")}
Here is code of sendMessageService:
#Named
public class SendMessageService {
private final MailServerManager mailServerManager;
private final MailQueue mailQueue;
private final VelocityManager velocityManager;
#Inject
public SendMessageService(#ComponentImport MailServerManager mailServerManager,
#ComponentImport MailQueue mailQueue,
#ComponentImport VelocityManager velocityManager) {
this.mailServerManager = mailServerManager;
this.mailQueue = mailQueue;
this.velocityManager = velocityManager;
}
What is the problem with VelocityManager? As I understand VelocityManager is not defined in the Spring Context, but it was in previous version, what can I do to add it?
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>xx.xxx.jira.plugins</groupId>
<artifactId>mail-handler</artifactId>
<version>1.0-SNAPSHOT</version>
<organization>
<name>Nane</name>
<url>http://</url>
</organization>
<name>Extended Mail Handler</name>
<description>
Provides basic "Create Issue or Comment Handler" functionality with additional features supported.
</description>
<packaging>atlassian-plugin</packaging>
<dependencies>
<!--JIRA Plugin dependencies-->
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-api</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-annotation</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>
<!--Mail handler plugin dependencies-->
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-mail-plugin</artifactId>
<version>${jira.mail.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.mail</groupId>
<artifactId>atlassian-mail</artifactId>
<version>4.0.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jta</groupId>
<artifactId>jta</artifactId>
<version>1.0.1b</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-jira-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<productVersion>${jira.version}</productVersion>
<productDataVersion>${jira.version}</productDataVersion>
<enableQuickReload>true</enableQuickReload>
<enableFastdev>false</enableFastdev>
<instructions>
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
<!-- Add package to export here -->
<Export-Package>
</Export-Package>
<!-- Add package import here -->
<Import-Package>
*
</Import-Package>
<!-- Ensure plugin is spring powered -->
<Spring-Context>*</Spring-Context>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<executions>
<execution>
<goals>
<goal>atlassian-spring-scanner</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jira.version>7.12.1</jira.version>
<amps.version>6.3.21</amps.version>
<jira.mail.version>10.0.13</jira.mail.version>
<plugin.testrunner.version>1.2.3</plugin.testrunner.version>
<atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version>
<!-- This key is used to keep the consistency between the key in atlassian-plugin.xml and the key to generate bundle. -->
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
If we look at the source of Jira, in ContainerRegistrar:
register.implementation(PROVIDED, VelocityManager.class, JiraVelocityManager.class);
The PROVIDED scope means that the component is published via OSGi.
Indeed I can create a trivial Jira plugin which imports a VelocityManager:
#Inject
public MyPluginComponentImpl(final ApplicationProperties applicationProperties, #ComponentImport VelocityManager velocityManager) {
this.applicationProperties = applicationProperties;
this.velocityManager = requireNonNull(velocityManager);
}
and setting a breakpoint in the constructor, see that an instance of JiraVelocityManager is being injected.
This is in Jira 8.13.2.
So what you are seeing shouldn't happen.
Can you add your pom.xml to your question, in particular the jira-maven-plugin configuration?
Also, check http://localhost:2990/jira/plugins/servlet/upm/osgi (substituting wherever your Jira is running) and check that the system bundle, Registered services section contains something like Service 501 com.atlassian.velocity.VelocityManager (the number might be different)
Update: Solved! Posted solution as my own answer. Will be accepting it in two days when I'm allowed to.
A little back story
I've been chasing down this rabbit hole for the past few days, and my question has drastically changed shape over that time. Initially, I thought I had an issue with Spring Boot, because it failed to parse one of my #Configuration annotated classes. Debugging that, I determined that Spring was looking in all the right places for one of my JAR-bound dependencies, but was coming up with a FileNotFoundException when trying to load a class from the JAR.
I was thrown off by this, because the JAR in question was quite verifiably on the classpath. I could print out the classpath during app startup, and see my JAR living nice and cozy inside.
So I simplified. And simplified. Eventually, I got things down to a project with two Java source files, and a tiny placeholder JAR pulled through Maven. This JAR only contains one file: tiny/jar/BaseTest.class.
This worked perfectly. From there, I swapped the dependency JAR on this small project. . . and startup failed. So I compared the JARs and noticed something odd.
The realization
While my small JAR contained a folder hierarchy of:
tiny/jar/BaseTest.class
The larger JAR looked like:
WEB-INF/classes/com/company/...
This WEB-INF/classes prefix is the poison which is killing Spring Boot's class loader. It expects to find classes starting from the root: com/company/... -- no prefix allowed.
I believe that Maven's dependency management is doing something tricky here. When my JAR is created using the clean install goal, it has the com/company/... root inside of it. If I manually copy this version of the JAR into my servers WEB-INF/lib folder, everything works, recognizes, and fires up perfectly.
But when Maven is used to bring in the dependency, WEB-INF/classes is prefixed on to my folder hierarchy, breaking everything.
The question
Does anyone know how I can prevent Maven from altering the directory structure of my JAR? The JAR is 100% correct until Maven pulls it in as a dependency, and suddenly the WEB-INF/classes prefix appears.
Here are the three POM files for reference. I've cut out a large swath of dependencies, but left everything else intact for easier reading.
Tiny Jar POM
<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>tiny</groupId>
<artifactId>jar</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<name>jar</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
Big Jar POM
<?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>com.company</groupId>
<artifactId>company-foundation</artifactId>
<version>0.7.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.4.0.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin> <!-- Sonar -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>2.5</version>
</plugin>
</plugins>
</build>
<repositories>
<!-- To use snapshots, you must also use the Sonatype Snapshots respository -->
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
Project POM
<?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>org.test</groupId>
<artifactId>dependency-issue</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>jar-dependency-issue</name>
<description>Barebones Spring Boot project used to demonstrate a JAR loading issue.</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>demo.JarDependencyIssueApplication</start-class>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- To run on a separate server, we need to mark tomcat starter as provided. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--
<dependency>
<groupId>com.company</groupId>
<artifactId>company-foundation</artifactId>
<version>0.7.0-SNAPSHOT</version>
</dependency>
-->
<dependency>
<groupId>tiny</groupId>
<artifactId>jar</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Solved my problem! I just got done poring over the configuring of my projects, comparing them for any suspicious deviations. Turns out that my larger JARs project in Eclipse had its Deployment Assembly (Found under Properties > Deployment Assembly) set to:
Source ============ Deploy Path
src/main/java --------> /WEB-INF/classes
src/main/resources -> /WEB-INF/classes
This caused my server to deploy the JAR into an internal /WEB-INF/classes folder.
Changing the Deploy Path setting to / fixed the problem! Everything is working perfectly now! Woo!
EDIT: The problem is now that even though start is called, https://github.com/ttiurani/neo4j-uuid/blob/master/src/main/java/org/neo4j/extension/uuid/UUIDTransactionEventHandler.java is activated only for an empty database of version 2.0.0-M03 (in 1.9.2 it is never called), and in there data.createdNodes() returns an empty iterator, even though a node was created. So it seems that there still is something wrong with registering a transaction event handler. I'm marking this as resolved, as the problem does not have anything to do with PluginLifecycle. I posted a new question here.
ORIGINAL:
I'm trying to get Neo4j to use a custom PluginLifecycle implementation in an embedded server. For some reason Neo4j calls the constructor of the implementation twice but never calls the start() method. The custom PluginLifecycle implementation is here:
https://github.com/ttiurani/neo4j-uuid/blob/master/src/main/java/org/neo4j/extension/uuid/UUIDPluginLifecycle.java
Here's a test project:
pom.xml:
<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>
<groupId>example</groupId>
<artifactId>neo4j-embedded-pluginlifecycle-test</artifactId>
<packaging>jar</packaging>
<name>Neo4j Embedded PluginLifecycle Implementation Test</name>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<neo4j.version>2.0.0-M03</neo4j.version>
</properties>
<repositories>
<repository>
<id>neo4j-public-repository</id>
<url>http://m2.neo4j.org</url>
</repository>
<repository>
<id>oss-sonatype-snapshots</id>
<name>OSS Sonatype Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
<!-- Neo4j graph database -->
<dependency>
<groupId>org.extendedmind</groupId>
<artifactId>neo4j-uuid</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>server-api</artifactId>
<version>${neo4j.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${neo4j.version}</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<classifier>static-web</classifier>
<version>${neo4j.version}</version>
</dependency>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
src/test/java/example/PluginLifecycleTest.java:
package example;
import org.junit.Test;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.kernel.GraphDatabaseAPI;
import org.neo4j.server.WrappingNeoServerBootstrapper;
import org.neo4j.server.configuration.Configurator;
import org.neo4j.server.configuration.ServerConfigurator;
public class PluginLifecycleTest{
#Test
public void shouldCreateUUIDToNewNode()
{
GraphDatabaseAPI graphdb = (GraphDatabaseAPI) new GraphDatabaseFactory()
.newEmbeddedDatabaseBuilder( "/tmp/neo4j-test" )
.newGraphDatabase();
new UUIDPluginLifecycle().start(graphdb, null);
ServerConfigurator config;
config = new ServerConfigurator( graphdb );
config.configuration().setProperty(
Configurator.THIRD_PARTY_PACKAGES_KEY, "org.neo4j.extension.uuid=/uuid");
config.configuration().setProperty(
Configurator.WEBSERVER_PORT_PROPERTY_KEY, 7473);
WrappingNeoServerBootstrapper srv = new WrappingNeoServerBootstrapper( graphdb, config );
srv.start();
Transaction tx = graphdb.beginTx();
Node node = graphdb.createNode();
node.setProperty("test", "test");
long id = node.getId();
tx.success();
tx = graphdb.beginTx();
node = graphdb.getNodeById(id);
node.getProperty("test");
// New nodes should have a "uuid" property
node.getProperty("uuid");
tx.success();
srv.stop();
}
}
For some reason this does not work with error "org.neo4j.graphdb.NotFoundException: org.neo4j.kernel.api.exceptions.PropertyKeyNotFoundException: Property key 'uuid' not found". I've tried with 1.9.2 but the problem persists.
Is there something else I need to do to get it to work?
You don't need the server component when trying to use neo4j-uuid in embedded mode. The simplest way would be to call:
GraphDatabaseService graphdb = new GraphDatabaseFactory()
.newEmbeddedDatabaseBuilder( "/tmp/neo4j-test" )
.newGraphDatabase();
new UUIDPluginLifecycle().start(graphDb, null);
and the UUID plugin should work.
If you need the server component additionally, e.g. you want to allow remote access, I have to do more debugging. My guess is that unmanaged extensions need to be packaged in a jar file.
I created a grails 1.2.0 project using the acegi plugin 0.5.2 which works very well.
To integrate the project into our companies build infrastructure I need to build it via maven. So I converted it to a maven project using the grails maven integration which worked quite well too.
There is one problem: I have a Java class CustomUserDetails that implements the GrailsUser interface. When maven tries to compile the project it can not find the GrailsUser interface class which is part of the acegi plugin.
Am I missing something or is there a problem with the grails maven integration that causes plugin classes missing from the classpath?
UPDATE: here is the pom.xml of my project:
<?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>
<groupId>com.troii</groupId>
<artifactId>testapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-crud</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-gorm</artifactId>
<version>1.2.0</version>
</dependency>
<!-- Grails defaults to Ehache for the second-level Hibernate cache. -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.3.1.GA</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.11.0.GA</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>1.7.1</version>
<exclusions>
<exclusion>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<artifactId>servlet-api</artifactId>
</exclusion>
<!-- We have JCL-over-SLF4J instead. -->
<exclusion>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- For ease of development and testing, we include the HSQLDB database. -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
</dependency>
<!-- Use Log4J for logging. This artifact also pulls in the Log4J JAR. -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<repositories>
<!-- Required to get hold of JTA -->
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2/</url>
<layout>default</layout>
</repository>
<repository>
<id>Codehaus Snapshots</id>
<url>http://snapshots.repository.codehaus.org</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>Codehaus Snapshots</id>
<url>http://snapshots.repository.codehaus.org</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<build>
<pluginManagement />
<plugins>
<plugin>
<groupId>org.grails</groupId>
<artifactId>grails-maven-plugin</artifactId>
<version>1.2.0</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>init</goal>
<goal>maven-clean</goal>
<goal>validate</goal>
<goal>config-directories</goal>
<goal>maven-compile</goal>
<goal>maven-test</goal>
<goal>maven-war</goal>
<goal>maven-functional-test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>tools</id>
<activation>
<property>
<name>java.vendor</name>
<value>Sun Microsystems Inc.</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${java.version}</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</profile>
</profiles>
</project>
I think what is going on is you are expecting the plugin classpath to be available to when compiling you project source code. Plugins have their own classloader, so your classes won't see stuff in there.
Instead define a project dependency to a library which contains the GrailsUser interface and make sure the scope of that dependency is compile (the default).