neo4j in JEE (JBoss) environment:

丶灬走出姿态 提交于 2020-01-06 04:29:10

问题


I have built a RESTful web service for Wildfly using Neo4j OGM, but when I access it I get a NullPointerException. It seems that a Map that should be populated with my model classes has not been initialized by the time it is accessed. Why is this happening?

Upfront I have to say that this module, salessupport-ui, is currently implemented as a fat client using javafx and it works fine connecting to the neo4j community edition 2.2.4, reading, writing, no problem. What I would like to do now and this is where I face problems, I want to use wildfly as a server which itself connects to neo4j, thus that the javafx client application sends requests only to the wildfly server. The protocol which I decided to use is REST, the implementation which is already kind-of provided on wildfly is resteasy.

Below are 1) the exception and some debugging info, 2) details about my context, project structure and the code for my classes.

1. Problem

Here are the exception and my findings when debugging.

Exception

Now when I call this REST service by entering http://localhost:8080/salessupport-restsvc/rest/address/list in the browser, the following exception is raised:

00:07:38,458 ERROR [io.undertow.request] (default task-5) UT005023: Exception handling request to /salessupport-restsvc/rest/address/list: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:212)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:149)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:372)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at org.neo4j.ogm.metadata.MetaData.entityType(MetaData.java:231)
at org.neo4j.ogm.session.Neo4jSession.entityType(Neo4jSession.java:451)
at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:55)
at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:94)
at org.neo4j.ogm.session.Neo4jSession.loadAll(Neo4jSession.java:114)
at groupid.salessupport.db.core.ApplicationContext$GraphRepositoryImpl.findAll(ApplicationContext.java:74)
at groupid.salessupport.restsvc.impl.SimpleRestGraphRepositoryImpl.findAll(SimpleRestGraphRepositoryImpl.java:29)
at groupid.salessupport.restsvc.impl.AddressRestImpl$Proxy$_$$_WeldClientProxy.findAll(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:137)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:296)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:250)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:237)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356)
... 32 more

Debugging info

  • By debugging I can see that it goes, as expected, to my first breakpoint in class SimpleRestGraphRepositoryImpl, method findAll() calling repository.findAll();
  • 2nd also expected, it goes to the inner GraphRepositoryImpl class to method findAll(...) and line context.getSession().loadAll(clazz); which creates a Session.
  • A few steps later it tries in org.neo4j.ogm.metadata.MetaData class in method _classInfo(String,String,String) to call domainInfo.getClassInfosWithAnnotation(nodeEntityAnnotation); where nodeEntityAnnotation="org.neo4j.ogm.annotation.NodeEntity".
  • In the DomainInfo class method getClassInfosWithAnnotation which is then invoked the map annotationNameToClassInfo is empty. I expect it to be filled with my models, which obviously happens in the javafx environment, but not in the JavaEE env.

here is that method

public List<ClassInfo> getClassInfosWithAnnotation(String annotation) {
    return annotationNameToClassInfo.get(annotation);
}

For checking, if the REST mechanism works as is I put a class next to the AddressRestImpl>

@Path("dummy")
public class DummyImpl {
    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Amount> getAll() {
        return Arrays.asList(new Amount());
    }
}

Calling this in the browser by navigating to http://localhost:8080/salessupport-restsvc/rest/dummy/list results in the expected: [{"amount":null,"currency":null}]

I have plenty of simple stuff to improve here, I have tried quite a lot of approaches, also on Tomcat 8 the same exception happens, but there the Rest approach did not work even in the dummy case so I switched to wildfly. Did I find a bug here or is there something simply I have missed in my setup?

2) Project and Code Details

Here is information about my environment, project structure and the code I run when I have this problem.

Environment

My environment is as follows:

I have Neo4J community edition 2.2.4.

I downloaded wildfly-9.0.1.Final and, except for a management port which conflicted with my NVidia Driver Software I left everything untouched.

Project Structure

I have a maven multimodule application which consists of the following modules:

<modules>
    <module>salessupport-ui</module>
    <module>salessupport-intf</module>
    <module>salessupport-db</module>
    <module>salessupport-restsvc</module>
</modules>

The dependencies are as follows:

salessupport-intf <-- salessupport-db
                          ^
                          |-- salessupport-ui
                          |-- salessupport-restsvc

Dependencies

Let me explain the dependencies:

salessupport parent has a dependency management definition like this:

<dependencyManagement>
    <dependencies>

        ...

        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-ogm</artifactId>
            <version>1.1.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.neo4j.app</groupId>
                    <artifactId>neo4j-server</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>

salessupport-intf uses the following dependencies:

<dependencies>
    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm</artifactId>
    </dependency>

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.0.0.GA</version>
    </dependency>

    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>jsr311-api</artifactId>
        <version>1.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.12</version>
    </dependency>

</dependencies>

salessupport-restsvc pom.xml is

<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>groupid</groupId>
    <artifactId>salessupport</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>salessupport-restsvc</artifactId>
<name>salessupport-restsvc</name>
<url>http://maven.apache.org</url>
<properties>
    <jersey.version>1.19</jersey.version>
    <resteasy.version>3.0.11.Final</resteasy.version>
</properties>

<dependencies>
    <dependency>
        <groupId>groupid</groupId>
        <artifactId>salessupport-intf</artifactId>
    </dependency>
    <dependency>
        <groupId>groupid</groupId>
        <artifactId>salessupport-db</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>${resteasy.version}</version>
        <scope>provided</scope>
        <exclusions>
            <exclusion>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>jaxrs-api</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-multipart-provider</artifactId>
        <version>${resteasy.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

<packaging>war</packaging>

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>${version.war.plugin}</version>
            <configuration>
                <!-- webXml>src\main\webapp\WEB-INF\web.xml</webXml -->
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <packagingExcludes>
                    org.neo4j.server.rest.discovery,
                    org.neo4j.server.rest.web
                </packagingExcludes>
            </configuration>
        </plugin>
    </plugins>
</build>
</project>

Code

Here are the relevant classes.

GraphRepository interface

I defined my custom GraphRepository interface:

public interface GraphRepository<S> {

    Iterable<S> findAll(Iterable<Long> nodeIds);

    Iterable<S> findAll();

    void delete(S arg0);

    S save(S arg0);

}

Model Classes

There are some model classes, e.g.:

package groupid.salessupport.db.model;

import java.text.DecimalFormat;

import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;

@NodeEntity(label="Amount")
public class Amount {

    @GraphId Long id;

    private Double amount;

    private Currency currency;

    public Currency getCurrency() {
        return currency;
    }

    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    public Double getAmount() {
        return amount;
    }

    public void setAmount(Double amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return new DecimalFormat().format(amount)+" "+currency;
    }

}

and

@NodeEntity(label="Currency")
public class Currency extends BaseObject {
    @Override
    public String toString() {
        return getName();
    }
}

Generic Simple Rest Graph Repository interface

public interface ISimpleRestGraphRepository<T> {
    @DELETE
    @Path("delete")
    @Consumes(MediaType.APPLICATION_JSON)
    public void delete(T arg0);

    @PUT
    @Path("save")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public T save(T arg0);

    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public Iterable<T> findAll();

    @POST
    @Path("listbyids")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Iterable<T> findAll(Iterable<Long> arg0);
}

REST Interface Definition for Amount

@Path("amount")
public interface AmountRest extends ISimpleRestGraphRepository<Amount> {
}

REST Activator

@ApplicationPath("/rest")
public class JaxRsActivator extends Application {
}

Generic implementation of my REST Service

@RequestScoped
public class SimpleRestGraphRepositoryImpl<T> implements ISimpleRestGraphRepository<T> {

    private final GraphRepository<T> repository;

    public SimpleRestGraphRepositoryImpl(GraphRepository<T> repository) {
        this.repository = repository;
    }

    @Override
    public void delete(T arg0) {
        repository.delete(arg0);
    }

    @Override
    public T save(T arg0) {
        return repository.save(arg0);
    }

    @Override
    public Iterable<T> findAll() {
        return repository.findAll();
    }

    @Override
    public Iterable<T> findAll(Iterable<Long> arg0) {
        return repository.findAll(arg0);
    }

}

... and the specific Implementation for Address:

public class AmountRestImpl extends SimpleRestGraphRepositoryImpl<Amount> implements AmountRest {

    public AmountRestImpl() {
        super(NeoRepositories.getInstance().getAmountRepository());
    }

}

DB Connection

in salessupport-db we connect to the database with some code:

public class ApplicationContext {
    private SessionFactory sessionFactory;
    private Session openSession;

    public ApplicationContext() {

    }

    public SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = new SessionFactory("groupid.salessupport.db.model");
        }
        return sessionFactory;
    }

    public Session getSession() {
        if (openSession == null) {
            openSession = getSessionFactory().openSession("http://localhost:7474",
                    "username", "password"); // it is not really like this     
    }
        return openSession;
    }

    public <S,G extends GraphRepository<S>> GraphRepository<S> getGraphRepository(Class<S> clazz) {
        return new GraphRepositoryImpl<S>(this, clazz);
    }

    public static class GraphRepositoryImpl<S> implements GraphRepository<S> {
        private ApplicationContext context;
        private Class<S> clazz;

        public GraphRepositoryImpl(ApplicationContext context, Class<S> clazz) {
            this.context = context;
            this.clazz = clazz;
        }

        @Override
        public Iterable<S> findAll(Iterable<Long> nodeIds) {
            List<Long> listNodeIds;
            if (nodeIds instanceof List) {
                listNodeIds = (List<Long>) nodeIds;
            } else {
                listNodeIds = new LinkedList<>();
                for (Long l : nodeIds) {
                    listNodeIds.add(l);
                }
            }
            return context.getSession().loadAll(clazz,listNodeIds);
        }

        @Override
        public Iterable<S> findAll() {
            return context.getSession().loadAll(clazz);
        }

        @Override
        public void delete(S arg0) {
            Session session = context.getSession();
            Transaction transaction = session.beginTransaction();
            context.getSession().delete(arg0);
            transaction.commit();
            transaction.close();
        }

        @Override
        public S save(S arg0) {
            Session session = context.getSession();
            Transaction transaction = session.beginTransaction();
            session.save(arg0);
            transaction.commit();
            transaction.close();
            return arg0;
        }

    }

}

Usage

Implementors acquire an instance of this GraphRepository quick and dirty with a "singleton":

public class NeoRepositories {
private ApplicationContext context;

private static final NeoRepositories INSTANCE = new NeoRepositories();

private NeoRepositories() {
    context = new ApplicationContext();
}

public GraphRepository<Person> getPersonRepository() {
    return context.getGraphRepository(Person.class);
}

public static NeoRepositories getInstance() {
    return INSTANCE;
}

public GraphRepository<Amount> getAmountRepository() {
    return context.getGraphRepository(Amount.class);
}
...
}

P.S.: It is my first question on stackoverflow, I hope I wrote as little and as much as necessary to convey the problem ...


回答1:


Is this @NodeEntity from Spring Data Neo4j? If yes, Spring must be setup correctly, which I cannot find here.




回答2:


In https://github.com/neo4j/neo4j-ogm/issues/48 there has been an update, which has been implemented with neo4j-ogm version >2 .

I made the whole sourcecode available on https://github.com/mkirchmann/hello-neo4j-ogm , No guarantee that everything is working or all is correct, at least listing the whole nodes for one type should be possible. And don't forget to set up ogm.properties correctly.

The key for the solution is the vfs driver for neo4j-ogm, which can be found in https://github.com/mkirchmann/neo4j-ogm-resourceresolver-vfs (it has been forked from ctpconsulting, use version 2.1.1 and mvn install in order to make it available in your local maven repository)

pom.xml

The following pom.xml is setting up the necessary (maybe more, not sure), so that a Rest call can be made successfully.

<?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>de.neuenberger</groupId>
<artifactId>hello-neo4j-ogm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloNeo4jOgmOnWildFly</name>
<description>Very Simple configuration to use neo4j ogm on WildFly application server</description>
<packaging>war</packaging>

<properties>
    <neo4jogmversion>2.1.1</neo4jogmversion>
    <resteasy.version>3.1.1.Final</resteasy.version>
    <version.war.plugin>3.0.0</version.war.plugin>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>${resteasy.version}</version>
        <scope>provided</scope>
        <exclusions>
            <exclusion>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-multipart-provider</artifactId>
        <version>${resteasy.version}</version>
        <scope>provided</scope>
    </dependency>


    <dependency>
        <groupId>com.ctp.neo4j</groupId>
        <artifactId>neo4j-ogm-resourceresolver-vfs</artifactId>
        <version>2.1.1</version>
    </dependency>

    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>2.2.4</version>
    </dependency>

    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm-core</artifactId>
        <version>${neo4jogmversion}</version>
    </dependency>
    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm-http-driver</artifactId>
        <version>${neo4jogmversion}</version>
    </dependency>

    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>${version.war.plugin}</version>
            <configuration>
                <!-- webXml>src\main\webapp\WEB-INF\web.xml</webXml -->
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <packagingExcludes>
                    org.neo4j.server.rest.discovery,
                    org.neo4j.server.rest.web
                </packagingExcludes>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

<repositories>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release</url>
    </repository>
    <repository>
        <id>neo4j</id>
        <name>Neo4j</name>
        <url>http://m2.neo4j.org/</url>
    </repository>
</repositories>

</project>

Thanks for everyones contribution and support!



来源:https://stackoverflow.com/questions/32490795/neo4j-in-jee-jboss-environment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!