DATAGRAPH-1102 - Apply Spring Data Code Formatting Settings.

This commit applied the Spring Data Code Formatting Settings
37b34a56ce/etc/ide
through the Eclipse Code Formatter for IDEA.

This closes #413.

# Conflicts:
#	pom.xml
#	spring-data-neo4j/pom.xml
This commit is contained in:
Michael J. Simons
2018-07-23 12:13:21 +02:00
parent 63b5e888ed
commit 673f08ecb2
193 changed files with 4256 additions and 4449 deletions

389
pom.xml
View File

@@ -1,214 +1,215 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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">
<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>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-parent</artifactId>
<version>4.2.14.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-parent</artifactId>
<version>4.2.14.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Data Neo4j</name>
<description>Neo4j support for Spring Data</description>
<url>http://projects.spring.io/spring-data-neo4j</url>
<name>Spring Data Neo4j</name>
<description>Neo4j support for Spring Data</description>
<url>http://projects.spring.io/spring-data-neo4j</url>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.9.14.BUILD-SNAPSHOT</version>
</parent>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.9.14.BUILD-SNAPSHOT</version>
</parent>
<modules>
<module>spring-data-neo4j</module>
<module>spring-data-neo4j-distribution</module>
</modules>
<modules>
<module>spring-data-neo4j</module>
<module>spring-data-neo4j-distribution</module>
</modules>
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-neo4j</dist.id>
<springdata.commons>1.13.14.BUILD-SNAPSHOT</springdata.commons>
<source.level>1.8</source.level>
</properties>
<properties>
<project.type>multi</project.type>
<dist.id>spring-data-neo4j</dist.id>
<springdata.commons>1.13.14.BUILD-SNAPSHOT</springdata.commons>
<source.level>1.8</source.level>
</properties>
<developers>
<developer>
<id>vbickers</id>
<name>Vince Bickers</name>
<email>vince at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>GMT</timezone>
</developer>
<developer>
<id>atg</id>
<name>Adam George</name>
<email>adam at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>GMT</timezone>
</developer>
<developer>
<id>bachmanm</id>
<name>Michal Bachman</name>
<email>michal at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>GMT</timezone>
</developer>
<developer>
<id>lmisquitta</id>
<name>Luanne Misquitta</name>
<email>luanne at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+5:30</timezone>
</developer>
<developer>
<id>mangrish</id>
<name>Mark Angrish</name>
<email>mark at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+11</timezone>
</developer>
<developer>
<id>jasperblues</id>
<name>Jasper Blues</name>
<email>jasper at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+8</timezone>
</developer>
<developer>
<id>mhunger</id>
<name>Michael Hunger</name>
<email>michael.hunger at neotechnology.com</email>
<organization>Neo Technology</organization>
<organizationUrl>http://www.neotechnology.com</organizationUrl>
<roles>
<role>Project Lead</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>ogierke</id>
<name>Oliver Gierke</name>
<email>ogierke at gopivotal.com</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>trisberg</id>
<name>Thomas Risberg</name>
<email>trisberg at gopivotal.com</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
<developer>
<id>mpollack</id>
<name>Mark Pollack</name>
<email>mpollack at gopivotal.com</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
</developers>
<developers>
<developer>
<id>vbickers</id>
<name>Vince Bickers</name>
<email>vince at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>GMT</timezone>
</developer>
<developer>
<id>atg</id>
<name>Adam George</name>
<email>adam at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>GMT</timezone>
</developer>
<developer>
<id>bachmanm</id>
<name>Michal Bachman</name>
<email>michal at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>GMT</timezone>
</developer>
<developer>
<id>lmisquitta</id>
<name>Luanne Misquitta</name>
<email>luanne at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+5:30</timezone>
</developer>
<developer>
<id>mangrish</id>
<name>Mark Angrish</name>
<email>mark at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+11</timezone>
</developer>
<developer>
<id>jasperblues</id>
<name>Jasper Blues</name>
<email>jasper at graphaware.com</email>
<organization>GraphAware</organization>
<organizationUrl>http://www.graphaware.com</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+8</timezone>
</developer>
<developer>
<id>mhunger</id>
<name>Michael Hunger</name>
<email>michael.hunger at neotechnology.com</email>
<organization>Neo Technology</organization>
<organizationUrl>http://www.neotechnology.com</organizationUrl>
<roles>
<role>Project Lead</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>ogierke</id>
<name>Oliver Gierke</name>
<email>ogierke at gopivotal.com</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>trisberg</id>
<name>Thomas Risberg</name>
<email>trisberg at gopivotal.com</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
<developer>
<id>mpollack</id>
<name>Mark Pollack</name>
<email>mpollack at gopivotal.com</email>
<organization>Pivotal</organization>
<organizationUrl>http://www.spring.io</organizationUrl>
<roles>
<role>Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
</developers>
<dependencyManagement>
<dependencyManagement>
<dependencies>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.2.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.2.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>
</dependencyManagement>
</dependencyManagement>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.jfrog.buildinfo</groupId>
<artifactId>artifactory-maven-plugin</artifactId>
<inherited>false</inherited>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.jfrog.buildinfo</groupId>
<artifactId>artifactory-maven-plugin</artifactId>
<inherited>false</inherited>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>neo4j</id>
<url>http://m2.neo4j.org/content/repositories/releases</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
<repository>
<id>neo4j-snapshots</id>
<url>http://m2.neo4j.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
<repositories>
<repository>
<id>neo4j</id>
<url>http://m2.neo4j.org/content/repositories/releases</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
<repository>
<id>neo4j-snapshots</id>
<url>http://m2.neo4j.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@@ -12,188 +12,189 @@
~
-->
<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">
<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>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-neo4j</artifactId>
<artifactId>spring-data-neo4j</artifactId>
<name>Spring Data Neo4J - Core</name>
<description>Neo4J support for Spring Data</description>
<name>Spring Data Neo4J - Core</name>
<description>Neo4J support for Spring Data</description>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-parent</artifactId>
<version>4.2.14.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-parent</artifactId>
<version>4.2.14.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<neo4j.ogm.version>2.1.6</neo4j.ogm.version>
<ogm.properties>ogm-http.properties</ogm.properties>
<project.root>${basedir}/..</project.root>
</properties>
<properties>
<neo4j.ogm.version>2.1.6</neo4j.ogm.version>
<ogm.properties>ogm-http.properties</ogm.properties>
<project.root>${basedir}/..</project.root>
</properties>
<dependencies>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<!-- CDI -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${cdi}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- CDI -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${cdi}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>${cdi}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>${cdi}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
<scope>test</scope>
</dependency>
<scope>test</scope>
</dependency>
<!-- Neo4j OGM -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>${neo4j.ogm.version}</version>
</dependency>
<!-- Neo4j OGM -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>${neo4j.ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-http-driver</artifactId>
<version>${neo4j.ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-http-driver</artifactId>
<version>${neo4j.ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-test</artifactId>
<version>${neo4j.ogm.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-security-enterprise</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-test</artifactId>
<version>${neo4j.ogm.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-security-enterprise</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>
<build>
<plugins>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<forkMode>once</forkMode>
<systemPropertyVariables>
<ogm.properties>${ogm.properties}</ogm.properties>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<forkMode>once</forkMode>
<systemPropertyVariables>
<ogm.properties>${ogm.properties}</ogm.properties>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -23,10 +23,11 @@ import org.springframework.data.annotation.QueryAnnotation;
/**
* Specifies the depth of the query. Used with derived finders.
*
* @author Luanne Misquitta
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@QueryAnnotation
@Documented
public @interface Depth {

View File

@@ -13,9 +13,13 @@
package org.springframework.data.neo4j.annotation;
import org.springframework.data.annotation.QueryAnnotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
import org.springframework.data.annotation.QueryAnnotation;
/**
* Annotation to declare finder queries directly on repository methods.
@@ -29,16 +33,16 @@ import java.lang.annotation.*;
@Documented
public @interface Query {
static final String CLASS = "org.springframework.data.neo4j.annotation.Query";
static final String VALUE = "value";
static final String CLASS = "org.springframework.data.neo4j.annotation.Query";
static final String VALUE = "value";
/**
* Defines the Cypher query to be executed when the annotated method is called.
*/
String value() default "";
/**
* Defines the Cypher query to be executed when the annotated method is called.
*/
String value() default "";
/**
* @return simpler count-query to be executed for @{see Pageable}-support
*/
String countQuery() default "";
/**
* @return simpler count-query to be executed for @{see Pageable}-support
*/
String countQuery() default "";
}

View File

@@ -13,7 +13,11 @@
package org.springframework.data.neo4j.annotation;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to be applied to interfaces and classes onto which arbitrary Cypher query results are to be mapped.
@@ -25,6 +29,6 @@ import java.lang.annotation.*;
@Documented
public @interface QueryResult {
// no annotation properties needed
// no annotation properties needed
}

View File

@@ -13,6 +13,8 @@
package org.springframework.data.neo4j.conversion;
import java.lang.reflect.ParameterizedType;
import org.neo4j.ogm.MetaData;
import org.neo4j.ogm.metadata.ClassInfo;
import org.neo4j.ogm.metadata.FieldInfo;
@@ -22,14 +24,12 @@ import org.neo4j.ogm.typeconversion.ConversionCallback;
import org.neo4j.ogm.typeconversion.ProxyAttributeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.convert.converter.Converter;
import java.lang.reflect.ParameterizedType;
import org.springframework.core.convert.support.GenericConversionService;
/**
* Specialisation of {@link GenericConversionService} that creates Spring-compatible converters from those known by the mapping
* {@link MetaData}, allowing the OGM type converters to be reused throughout a Spring application.
* Specialisation of {@link GenericConversionService} that creates Spring-compatible converters from those known by the
* mapping {@link MetaData}, allowing the OGM type converters to be reused throughout a Spring application.
*
* @author Adam George
* @author Luanne Misquitta
@@ -37,86 +37,83 @@ import java.lang.reflect.ParameterizedType;
*/
public class MetaDataDrivenConversionService extends GenericConversionService implements ConversionCallback {
private static final Logger logger = LoggerFactory.getLogger(MetaDataDrivenConversionService.class);
private static final Logger logger = LoggerFactory.getLogger(MetaDataDrivenConversionService.class);
/**
* Constructs a new {@link MetaDataDrivenConversionService} based on the given {@link MetaData}.
*
* @param metaData The OGM {@link MetaData} from which to elicit type converters configured in the underlying object-graph
* mapping layer
*/
public MetaDataDrivenConversionService(MetaData metaData) {
metaData.registerConversionCallback(this);
/**
* Constructs a new {@link MetaDataDrivenConversionService} based on the given {@link MetaData}.
*
* @param metaData The OGM {@link MetaData} from which to elicit type converters configured in the underlying
* object-graph mapping layer
*/
public MetaDataDrivenConversionService(MetaData metaData) {
metaData.registerConversionCallback(this);
for (ClassInfo classInfo : metaData.persistentEntities()) {
for (FieldInfo fieldInfo : classInfo.propertyFields()) {
if (fieldInfo.hasPropertyConverter()) {
addWrappedConverter(fieldInfo.getPropertyConverter());
}
}
// TODO: do we need to check the setters too or are programmers obliged to annotate both?
for (MethodInfo methodInfo : classInfo.propertyGetters()) {
if (methodInfo.hasPropertyConverter()) {
addWrappedConverter(methodInfo.getPropertyConverter());
}
}
}
}
for (ClassInfo classInfo : metaData.persistentEntities()) {
for (FieldInfo fieldInfo : classInfo.propertyFields()) {
if (fieldInfo.hasPropertyConverter()) {
addWrappedConverter(fieldInfo.getPropertyConverter());
}
}
// TODO: do we need to check the setters too or are programmers obliged to annotate both?
for (MethodInfo methodInfo : classInfo.propertyGetters()) {
if (methodInfo.hasPropertyConverter()) {
addWrappedConverter(methodInfo.getPropertyConverter());
}
}
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void addWrappedConverter(final AttributeConverter attributeConverter) {
if (attributeConverter instanceof ProxyAttributeConverter) {
return;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void addWrappedConverter(final AttributeConverter attributeConverter) {
if (attributeConverter instanceof ProxyAttributeConverter) {
return;
}
Converter toGraphConverter = new Converter() {
@Override
public Object convert(Object source) {
return attributeConverter.toGraphProperty(source);
}
};
Converter toEntityConverter = new Converter() {
@Override
public Object convert(Object source) {
return attributeConverter.toEntityAttribute(source);
}
};
Converter toGraphConverter = new Converter() {
@Override
public Object convert(Object source) {
return attributeConverter.toGraphProperty(source);
}
};
Converter toEntityConverter = new Converter() {
@Override
public Object convert(Object source) {
return attributeConverter.toEntityAttribute(source);
}
};
ParameterizedType pt = (ParameterizedType) attributeConverter.getClass().getGenericInterfaces()[0];
Class<?> sourceType, targetType;
if (pt.getActualTypeArguments()[0] instanceof Class) {
sourceType = (Class<?>) pt.getActualTypeArguments()[0];
} else { // the argument may be a Collection for example
sourceType = (Class<?>) ((ParameterizedType) pt.getActualTypeArguments()[0]).getActualTypeArguments()[0];
}
ParameterizedType pt = (ParameterizedType) attributeConverter.getClass().getGenericInterfaces()[0];
Class<?> sourceType, targetType;
if (pt.getActualTypeArguments()[0] instanceof Class) {
sourceType = (Class<?>) pt.getActualTypeArguments()[0];
}
else { //the argument may be a Collection for example
sourceType = (Class<?>)((ParameterizedType) pt.getActualTypeArguments()[0]).getActualTypeArguments()[0];
}
if (pt.getActualTypeArguments()[1] instanceof Class) {
targetType = (Class<?>) pt.getActualTypeArguments()[1];
} else {
targetType = (Class<?>) ((ParameterizedType) pt.getActualTypeArguments()[1]).getActualTypeArguments()[1];
if (pt.getActualTypeArguments()[1] instanceof Class) {
targetType = (Class<?>) pt.getActualTypeArguments()[1];
}
else {
targetType = (Class<?>)((ParameterizedType) pt.getActualTypeArguments()[1]).getActualTypeArguments()[1];
}
}
if (canConvert(sourceType, targetType) && canConvert(targetType, sourceType)) {
logger.info("Not adding Spring-compatible converter for " + attributeConverter.getClass()
+ " because one that does the same job has already been registered with the ConversionService.");
} else {
// It could be argued that this is wrong as it potentially overrides a registered converted that doesn't handle
// both directions, but I've decided that it's better to ensure the same converter is used for load and save.
addConverter(sourceType, targetType, toGraphConverter);
addConverter(targetType, sourceType, toEntityConverter);
}
}
if (canConvert(sourceType, targetType) && canConvert(targetType, sourceType)) {
logger.info("Not adding Spring-compatible converter for " + attributeConverter.getClass()
+ " because one that does the same job has already been registered with the ConversionService.");
} else {
// It could be argued that this is wrong as it potentially overrides a registered converted that doesn't handle
// both directions, but I've decided that it's better to ensure the same converter is used for load and save.
addConverter(sourceType, targetType, toGraphConverter);
addConverter(targetType, sourceType, toEntityConverter);
}
}
@Override
public <T> T convert(Class<T> targetType, Object value) {
if (value == null) {
return null;
}
return convert(value, targetType);
}
@Override
public <T> T convert(Class<T> targetType, Object value) {
if (value == null) {
return null;
}
return convert(value, targetType);
}
}

View File

@@ -11,15 +11,14 @@
*
*/
package org.springframework.data.neo4j.conversion;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
import org.springframework.data.geo.Point;
import java.util.HashMap;
import java.util.Map;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
import org.springframework.data.geo.Point;
/**
* Converts latitude and longitude properties on a node entity to an instance of Point and vice-versa.
*
@@ -28,24 +27,24 @@ import java.util.Map;
*/
public class PointConverter implements CompositeAttributeConverter<Point> {
@Override
public Map<String, ?> toGraphProperties(Point point) {
Map<String, Double> properties = new HashMap<>();
if (point != null) {
properties.put("latitude", point.getX());
properties.put("longitude", point.getY());
}
return properties;
}
@Override
public Map<String, ?> toGraphProperties(Point point) {
Map<String, Double> properties = new HashMap<>();
if (point != null) {
properties.put("latitude", point.getX());
properties.put("longitude", point.getY());
}
return properties;
}
@Override
public Point toEntityAttribute(Map<String, ?> map) {
Double latitude = (Double) map.get("latitude");
Double longitude = (Double) map.get("longitude");
if (latitude != null && longitude != null) {
return new Point(latitude, longitude);
}
return null;
}
@Override
public Point toEntityAttribute(Map<String, ?> map) {
Double latitude = (Double) map.get("latitude");
Double longitude = (Double) map.get("longitude");
if (latitude != null && longitude != null) {
return new Point(latitude, longitude);
}
return null;
}
}
}

View File

@@ -60,14 +60,18 @@ public class Neo4jErrorStatusCodes {
errors.put("Neo.ClientError.Statement.SemanticError", NonTransientDataAccessException.class);
errors.put("Neo.ClientError.Statement.SyntaxError", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Statement.TypeError", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.ForbiddenDueToTransactionType", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionAccessedConcurrently", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionEventHandlerFailed", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.ForbiddenDueToTransactionType",
InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionAccessedConcurrently",
InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionEventHandlerFailed",
InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionHookFailed", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionMarkedAsFailed", ConcurrencyFailureException.class);
errors.put("Neo.ClientError.Transaction.TransactionNotFound", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionTerminated", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionValidationFailed", InvalidDataAccessResourceUsageException.class);
errors.put("Neo.ClientError.Transaction.TransactionValidationFailed",
InvalidDataAccessResourceUsageException.class);
errors.put("Neo.DatabaseError.General.IndexCorruptionDetected", DataAccessResourceFailureException.class);
errors.put("Neo.DatabaseError.General.SchemaCorruptionDetected", DataAccessResourceFailureException.class);
errors.put("Neo.DatabaseError.General.UnknownError", UncategorizedDataAccessException.class);

View File

@@ -12,8 +12,13 @@
*/
package org.springframework.data.neo4j.mapping;
import org.neo4j.ogm.annotation.typeconversion.Convert;
import static java.util.Collections.*;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.neo4j.ogm.MetaData;
import org.neo4j.ogm.annotation.typeconversion.Convert;
import org.neo4j.ogm.classloader.MetaDataClassLoader;
import org.neo4j.ogm.metadata.ClassInfo;
import org.neo4j.ogm.metadata.FieldInfo;
@@ -23,17 +28,10 @@ import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import static java.util.Collections.singleton;
/**
* This class implements Spring Data's MappingContext interface, scavenging the required data from the OGM's metadata in order
* to for SDN to play nicely with Spring Data REST.
*
* The main thing to note is that this class is effectively a container shim for {@code ClassInfo} objects. We don't reload all
* the mapping information again.
* This class implements Spring Data's MappingContext interface, scavenging the required data from the OGM's metadata in
* order to for SDN to play nicely with Spring Data REST. The main thing to note is that this class is effectively a
* container shim for {@code ClassInfo} objects. We don't reload all the mapping information again.
*
* @author Vince Bickers
* @author Adam George
@@ -41,88 +39,90 @@ import static java.util.Collections.singleton;
*/
public class Neo4jMappingContext extends AbstractMappingContext<Neo4jPersistentEntity<?>, Neo4jPersistentProperty> {
private static final Logger logger = LoggerFactory.getLogger(Neo4jMappingContext.class);
private static final Logger logger = LoggerFactory.getLogger(Neo4jMappingContext.class);
private final MetaData metaData;
private final MetaData metaData;
/**
* Constructs a new {@link Neo4jMappingContext} based on the persistent entities in the given {@link MetaData}.
*
* @param metaData The OGM {@link MetaData} from which to extract the persistent entities
*/
public Neo4jMappingContext(MetaData metaData) {
this.metaData = metaData;
/**
* Constructs a new {@link Neo4jMappingContext} based on the persistent entities in the given {@link MetaData}.
*
* @param metaData The OGM {@link MetaData} from which to extract the persistent entities
*/
public Neo4jMappingContext(MetaData metaData) {
this.metaData = metaData;
for (ClassInfo classInfo : metaData.persistentEntities()) {
try {
addPersistentEntity( MetaDataClassLoader.loadClass( classInfo.name() ));
} catch (ClassNotFoundException e) {
logger.error("Failed to load class: " + classInfo.name() + " named in ClassInfo due to exception", e);
}
}
for (ClassInfo classInfo : metaData.persistentEntities()) {
try {
addPersistentEntity(MetaDataClassLoader.loadClass(classInfo.name()));
} catch (ClassNotFoundException e) {
logger.error("Failed to load class: " + classInfo.name() + " named in ClassInfo due to exception", e);
}
}
logger.info("Neo4jMappingContext initialisation completed");
}
logger.info("Neo4jMappingContext initialisation completed");
}
@Override
protected <T> Neo4jPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
logger.debug("Creating Neo4jPersistentEntity from type information: {}", typeInformation);
return new Neo4jPersistentEntity<>(typeInformation);
}
@Override
protected <T> Neo4jPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
logger.debug("Creating Neo4jPersistentEntity from type information: {}", typeInformation);
return new Neo4jPersistentEntity<>(typeInformation);
}
@Override
protected Neo4jPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, Neo4jPersistentEntity<?> owner,
SimpleTypeHolder simpleTypeHolder) {
@Override
protected Neo4jPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
Neo4jPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
ClassInfo owningClassInfo = this.metaData.classInfo(owner.getType().getName());
ClassInfo owningClassInfo = this.metaData.classInfo(owner.getType().getName());
Field propertyField = field;
if (propertyField == null && owningClassInfo != null && descriptor != null) {
FieldInfo fieldInfo = owningClassInfo.propertyFieldByName(descriptor.getName());
if (fieldInfo == null) {
fieldInfo = owningClassInfo.relationshipFieldByName(descriptor.getName());
}
if (fieldInfo != null) {
propertyField = owningClassInfo.getField(fieldInfo);
} else {
// there is no field, probably because descriptor gave us a field name derived from a getter
logger.debug("Couldn't resolve a concrete field corresponding to property {} on {} ",
descriptor.getName(), owningClassInfo.name());
}
}
Field propertyField = field;
if (propertyField == null && owningClassInfo != null && descriptor != null) {
FieldInfo fieldInfo = owningClassInfo.propertyFieldByName(descriptor.getName());
if (fieldInfo == null) {
fieldInfo = owningClassInfo.relationshipFieldByName(descriptor.getName());
}
if (fieldInfo != null) {
propertyField = owningClassInfo.getField(fieldInfo);
} else {
// there is no field, probably because descriptor gave us a field name derived from a getter
logger.debug("Couldn't resolve a concrete field corresponding to property {} on {} ", descriptor.getName(),
owningClassInfo.name());
}
}
return new Neo4jPersistentProperty(owningClassInfo, propertyField, descriptor, owner,
updateSimpleTypeHolder(simpleTypeHolder, propertyField));
}
return new Neo4jPersistentProperty(owningClassInfo, propertyField, descriptor, owner,
updateSimpleTypeHolder(simpleTypeHolder, propertyField));
}
private SimpleTypeHolder updateSimpleTypeHolder(SimpleTypeHolder currentSimpleTypeHolder, Field field) {
if (field == null) {
return currentSimpleTypeHolder;
}
private SimpleTypeHolder updateSimpleTypeHolder(SimpleTypeHolder currentSimpleTypeHolder, Field field) {
if (field == null) {
return currentSimpleTypeHolder;
}
final Class<?> fieldType = field.getType().isArray() ? field.getType().getComponentType() : field.getType();
final Class<?> fieldType = field.getType().isArray() ? field.getType().getComponentType() : field.getType();
if (shouldUpdateSimpleTypes(currentSimpleTypeHolder, field, fieldType)) {
SimpleTypeHolder updatedSimpleTypeHolder = new SimpleTypeHolder(singleton(fieldType), currentSimpleTypeHolder);
setSimpleTypeHolder(updatedSimpleTypeHolder);
return updatedSimpleTypeHolder;
}
return currentSimpleTypeHolder;
}
if (shouldUpdateSimpleTypes(currentSimpleTypeHolder, field, fieldType)) {
SimpleTypeHolder updatedSimpleTypeHolder = new SimpleTypeHolder(singleton(fieldType), currentSimpleTypeHolder);
setSimpleTypeHolder(updatedSimpleTypeHolder);
return updatedSimpleTypeHolder;
}
return currentSimpleTypeHolder;
}
private boolean shouldUpdateSimpleTypes(SimpleTypeHolder currentSimpleTypeHolder, Field field, Class<?> rawFieldType) {
if (field.isAnnotationPresent(Convert.class)) {
return true;
}
private boolean shouldUpdateSimpleTypes(SimpleTypeHolder currentSimpleTypeHolder, Field field,
Class<?> rawFieldType) {
if (field.isAnnotationPresent(Convert.class)) {
return true;
}
if (currentSimpleTypeHolder.isSimpleType(rawFieldType) || rawFieldType.isInterface()) {
return false;
}
if (this.metaData.classInfo(rawFieldType.getName()) == null) {
logger.info("No class information found in OGM meta-data for {} so treating as simple type for SD Commons", rawFieldType);
return true;
}
return false;
}
if (currentSimpleTypeHolder.isSimpleType(rawFieldType) || rawFieldType.isInterface()) {
return false;
}
if (this.metaData.classInfo(rawFieldType.getName()) == null) {
logger.info("No class information found in OGM meta-data for {} so treating as simple type for SD Commons",
rawFieldType);
return true;
}
return false;
}
}

View File

@@ -19,22 +19,20 @@ import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.util.TypeInformation;
/**
* This class implements Spring Data's PersistentEntity interface, scavenging the required data from the OGM's mapping classes
* in order to for SDN to play nicely with Spring Data REST.
*
* The main thing to note is that this class is effectively a shim for ClassInfo. We don't reload all the mapping information
* again.
* This class implements Spring Data's PersistentEntity interface, scavenging the required data from the OGM's mapping
* classes in order to for SDN to play nicely with Spring Data REST. The main thing to note is that this class is
* effectively a shim for ClassInfo. We don't reload all the mapping information again.
* <p>
* These attributes do not appear to be used/needed for SDN 4 to inter-operate correctly with SD-REST:
* </p>
* <ul>
* <li>typeAlias</li>
* <li>typeInformation</li>
* <li>preferredConstructor (we always use the default constructor)</li>
* <li>versionProperty</li>
* <li>typeAlias</li>
* <li>typeInformation</li>
* <li>preferredConstructor (we always use the default constructor)</li>
* <li>versionProperty</li>
* </ul>
* Consequently their associated getter methods always return default values of null or [true|false] However, because these
* method calls are not expected, we also log a warning message if they get invoked
* Consequently their associated getter methods always return default values of null or [true|false] However, because
* these method calls are not expected, we also log a warning message if they get invoked
*
* @author Vince Bickers
* @author Adam George
@@ -42,33 +40,33 @@ import org.springframework.data.util.TypeInformation;
*/
public class Neo4jPersistentEntity<T> extends BasicPersistentEntity<T, Neo4jPersistentProperty> {
private static final Logger logger = LoggerFactory.getLogger(Neo4jPersistentEntity.class);
private static final Logger logger = LoggerFactory.getLogger(Neo4jPersistentEntity.class);
/**
* Constructs a new {@link Neo4jPersistentEntity} based on the given type information.
*
* @param information The {@link TypeInformation} upon which to base this persistent entity.
*/
public Neo4jPersistentEntity(TypeInformation<T> information) {
super(information);
}
/**
* Constructs a new {@link Neo4jPersistentEntity} based on the given type information.
*
* @param information The {@link TypeInformation} upon which to base this persistent entity.
*/
public Neo4jPersistentEntity(TypeInformation<T> information) {
super(information);
}
@Override
public boolean hasVersionProperty() {
logger.debug("[entity].hasVersionProperty() returns false"); // by design
return false;
}
@Override
public boolean hasVersionProperty() {
logger.debug("[entity].hasVersionProperty() returns false"); // by design
return false;
}
@Override
public Neo4jPersistentProperty getVersionProperty() {
logger.debug("[entity].getVersionProperty() returns null"); // by design
return null;
}
@Override
public Neo4jPersistentProperty getVersionProperty() {
logger.debug("[entity].getVersionProperty() returns null"); // by design
return null;
}
@Override
public boolean isVersionProperty(PersistentProperty<?> property) {
logger.debug("[entity].isIdProperty({}) returns false", property); // again, by design
return false;
}
@Override
public boolean isVersionProperty(PersistentProperty<?> property) {
logger.debug("[entity].isIdProperty({}) returns false", property); // again, by design
return false;
}
}

View File

@@ -29,11 +29,10 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.neo4j.annotation.QueryResult;
/**
* This class implements Spring Data's PersistentProperty interface, scavenging the required data from the
* OGM's mapping classes in order to for SDN to play nicely with Spring Data REST.
* The main thing to note is that this class is effectively a shim for FieldInfo. We don't reload
* all the mapping information again.
* We do not yet support getter/setter access to entity properties.
* This class implements Spring Data's PersistentProperty interface, scavenging the required data from the OGM's mapping
* classes in order to for SDN to play nicely with Spring Data REST. The main thing to note is that this class is
* effectively a shim for FieldInfo. We don't reload all the mapping information again. We do not yet support
* getter/setter access to entity properties.
* <p>
* These attributes do not appear to be used/needed for SDN 4 to inter-operate correctly with SD-REST:
* </p>
@@ -44,8 +43,8 @@ import org.springframework.data.neo4j.annotation.QueryResult;
* <li>isTransient (we never supply transient classes to the Spring mapping context)</li>
* <li>isWritable (we don't currently support read-only fields)</li>
* </ul>
* Consequently their associated getter methods always return default values of null or [true|false]
* However, because these method calls are not expected, we also log a warning message if they get invoked
* Consequently their associated getter methods always return default values of null or [true|false] However, because
* these method calls are not expected, we also log a warning message if they get invoked
*
* @author Vince Bickers
* @author Adam George
@@ -66,17 +65,22 @@ public class Neo4jPersistentProperty extends AnnotationBasedPersistentProperty<N
* @param field The property {@link Field}
* @param descriptor The Java bean {@link PropertyDescriptor}
* @param owner The owning {@link PersistentEntity} that corresponds to the given {@code ClassInfo}
* @param simpleTypeHolder The {@link SimpleTypeHolder} that dictates whether the type of this property is considered simple
* or not
* @param simpleTypeHolder The {@link SimpleTypeHolder} that dictates whether the type of this property is considered
* simple or not
*/
public Neo4jPersistentProperty(ClassInfo owningClassInfo, Field field, PropertyDescriptor descriptor,
PersistentEntity<?, Neo4jPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
PersistentEntity<?, Neo4jPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, descriptor, owner, simpleTypeHolder);
if (owningClassInfo == null) {
logger.warn("Owning ClassInfo is null for field: {} and propertyDescriptor: {}", field, descriptor);
}
if ((owningClassInfo != null && owningClassInfo.getUnderlyingClass() != null && simpleTypeHolder.isSimpleType(owningClassInfo.getUnderlyingClass()))
|| owner.getType().isEnum()) { //TODO refactor all these null checks
if ((owningClassInfo != null && owningClassInfo.getUnderlyingClass() != null
&& simpleTypeHolder.isSimpleType(owningClassInfo.getUnderlyingClass())) || owner.getType().isEnum()) { // TODO
// refactor
// all
// these
// null
// checks
this.isIdProperty = false;
} else {
this.isIdProperty = resolveWhetherIdProperty(owningClassInfo, field);
@@ -84,7 +88,8 @@ public class Neo4jPersistentProperty extends AnnotationBasedPersistentProperty<N
}
private static boolean resolveWhetherIdProperty(ClassInfo owningClassInfo, Field field) {
if (owningClassInfo == null || owningClassInfo.isInterface() || owningClassInfo.annotationsInfo().get(QueryResult.class.getName()) != null || owningClassInfo.isEnum()) {
if (owningClassInfo == null || owningClassInfo.isInterface()
|| owningClassInfo.annotationsInfo().get(QueryResult.class.getName()) != null || owningClassInfo.isEnum()) {
// no ID properties on @QueryResult or non-concrete objects
return false;
} else {
@@ -122,8 +127,8 @@ public class Neo4jPersistentProperty extends AnnotationBasedPersistentProperty<N
}
/**
* Determines whether or not this property should be considered an association to another entity or whether it's
* just a simple property that should be shown as a value.
* Determines whether or not this property should be considered an association to another entity or whether it's just
* a simple property that should be shown as a value.
* <p>
* This implementation works by looking for non-transient members annotated with <code>@Relationship</code>.
* </p>
@@ -132,10 +137,8 @@ public class Neo4jPersistentProperty extends AnnotationBasedPersistentProperty<N
*/
@Override
public boolean isAssociation() {
return !isTransient() &&
(isAnnotationPresent(Relationship.class)
|| isAnnotationPresent(StartNode.class)
|| isAnnotationPresent(EndNode.class));
return !isTransient() && (isAnnotationPresent(Relationship.class) || isAnnotationPresent(StartNode.class)
|| isAnnotationPresent(EndNode.class));
}
@Override

View File

@@ -13,7 +13,6 @@
package org.springframework.data.neo4j.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -40,7 +39,6 @@ public interface GraphRepository<T> extends Neo4jRepository<T, Long> {
Iterable<T> findAll(Sort sort, int depth);
Iterable<T> findAll(Iterable<Long> ids);
Iterable<T> findAll(Iterable<Long> ids, int depth);
@@ -51,7 +49,8 @@ public interface GraphRepository<T> extends Neo4jRepository<T, Long> {
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for accuracy.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for
* accuracy.
*
* @param pageable
* @return a page of entities
@@ -60,7 +59,8 @@ public interface GraphRepository<T> extends Neo4jRepository<T, Long> {
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for accuracy.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for
* accuracy.
*
* @param pageable
* @param depth

View File

@@ -54,7 +54,8 @@ public interface Neo4jRepository<T, ID extends Serializable> extends PagingAndSo
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for accuracy.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for
* accuracy.
*
* @param pageable
* @return a page of entities
@@ -63,7 +64,8 @@ public interface Neo4jRepository<T, ID extends Serializable> extends PagingAndSo
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for accuracy.
* {@link Page#getTotalPages()} returns an estimation of the total number of pages and should not be relied upon for
* accuracy.
*
* @param pageable
* @param depth

View File

@@ -16,16 +16,17 @@
package org.springframework.data.neo4j.repository.cdi;
import org.neo4j.ogm.session.Session;
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactory;
import org.springframework.data.repository.cdi.CdiRepositoryBean;
import org.springframework.data.repository.config.CustomRepositoryImplementationDetector;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import java.lang.annotation.Annotation;
import java.util.Set;
import org.neo4j.ogm.session.Session;
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactory;
import org.springframework.data.repository.cdi.CdiRepositoryBean;
import org.springframework.data.repository.config.CustomRepositoryImplementationDetector;
/**
* {@link org.springframework.data.repository.cdi.CdiRepositoryBean} to create Neo4j repository instances via CDI.
@@ -34,30 +35,30 @@ import java.util.Set;
* @since 4.2
*/
public class Neo4jCdiRepositoryBean<T> extends CdiRepositoryBean<T> {
private final Bean<Session> sessionBean;
private final Bean<Session> sessionBean;
/**
* Creates a new {@link Neo4jCdiRepositoryBean}.
*
* @param sessionBean must not be {@literal null}.
* @param qualifiers must not be {@literal null}.
* @param repositoryType must not be {@literal null}.
* @param beanManager must not be {@literal null}.
* @param detector detector for the custom {@link org.springframework.data.repository.Repository} implementations
* {@link CustomRepositoryImplementationDetector}, can be {@literal null}.
*/
public Neo4jCdiRepositoryBean(Bean<Session> sessionBean, Set<Annotation> qualifiers, Class<T> repositoryType,
BeanManager beanManager, CustomRepositoryImplementationDetector detector) {
super(qualifiers, repositoryType, beanManager, detector);
this.sessionBean = sessionBean;
}
/**
* Creates a new {@link Neo4jCdiRepositoryBean}.
*
* @param sessionBean must not be {@literal null}.
* @param qualifiers must not be {@literal null}.
* @param repositoryType must not be {@literal null}.
* @param beanManager must not be {@literal null}.
* @param detector detector for the custom {@link org.springframework.data.repository.Repository} implementations
* {@link CustomRepositoryImplementationDetector}, can be {@literal null}.
*/
public Neo4jCdiRepositoryBean(Bean<Session> sessionBean, Set<Annotation> qualifiers, Class<T> repositoryType,
BeanManager beanManager, CustomRepositoryImplementationDetector detector) {
super(qualifiers, repositoryType, beanManager, detector);
this.sessionBean = sessionBean;
}
@Override
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType, Object customImplementation) {
@Override
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType, Object customImplementation) {
Session session = getDependencyInstance(sessionBean, Session.class);
Session session = getDependencyInstance(sessionBean, Session.class);
Neo4jRepositoryFactory factory = new Neo4jRepositoryFactory(session);
return factory.getRepository(repositoryType, customImplementation);
}
Neo4jRepositoryFactory factory = new Neo4jRepositoryFactory(session);
return factory.getRepository(repositoryType, customImplementation);
}
}

View File

@@ -16,18 +16,6 @@
package org.springframework.data.neo4j.repository.cdi;
import org.neo4j.ogm.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.repository.cdi.CdiRepositoryBean;
import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.UnsatisfiedResolutionException;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.ProcessBean;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
@@ -36,6 +24,19 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.UnsatisfiedResolutionException;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.ProcessBean;
import org.neo4j.ogm.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.repository.cdi.CdiRepositoryBean;
import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
/**
* CDI extension to export Neo4j repositories.
*
@@ -44,68 +45,66 @@ import java.util.Set;
*/
public class Neo4jCdiRepositoryExtension extends CdiRepositoryExtensionSupport {
private static final Logger LOG = LoggerFactory.getLogger(Neo4jCdiRepositoryExtension.class);
private final Map<Set<Annotation>, Bean<Session>> sessions = new HashMap<Set<Annotation>, Bean<Session>>();
private static final Logger LOG = LoggerFactory.getLogger(Neo4jCdiRepositoryExtension.class);
private final Map<Set<Annotation>, Bean<Session>> sessions = new HashMap<Set<Annotation>, Bean<Session>>();
public Neo4jCdiRepositoryExtension() {
LOG.info("Activating CDI extension for Spring Data Neo4j repositories.");
}
public Neo4jCdiRepositoryExtension() {
LOG.info("Activating CDI extension for Spring Data Neo4j repositories.");
}
@SuppressWarnings("unchecked")
<X> void processBean(@Observes ProcessBean<X> processBean) {
Bean<X> bean = processBean.getBean();
@SuppressWarnings("unchecked")
<X> void processBean(@Observes ProcessBean<X> processBean) {
Bean<X> bean = processBean.getBean();
for (Type type : bean.getTypes()) {
if (type instanceof Class<?> && Session.class.isAssignableFrom((Class<?>) type)) {
for (Type type : bean.getTypes()) {
if (type instanceof Class<?> && Session.class.isAssignableFrom((Class<?>) type)) {
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Discovered %s with qualifiers %s.", Session.class.getName(),
bean.getQualifiers()));
}
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Discovered %s with qualifiers %s.", Session.class.getName(), bean.getQualifiers()));
}
sessions.put(new HashSet<Annotation>(bean.getQualifiers()), (Bean<Session>) bean);
}
}
}
sessions.put(new HashSet<Annotation>(bean.getQualifiers()), (Bean<Session>) bean);
}
}
}
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
for (Entry<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
for (Entry<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
Class<?> repositoryType = entry.getKey();
Set<Annotation> qualifiers = entry.getValue();
Class<?> repositoryType = entry.getKey();
Set<Annotation> qualifiers = entry.getValue();
// Create the bean representing the repository.
CdiRepositoryBean<?> repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager);
if (LOG.isInfoEnabled()) {
LOG.info(String.format("Registering bean for %s with qualifiers %s.", repositoryType.getName(),
qualifiers));
}
// Create the bean representing the repository.
CdiRepositoryBean<?> repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager);
if (LOG.isInfoEnabled()) {
LOG.info(String.format("Registering bean for %s with qualifiers %s.", repositoryType.getName(), qualifiers));
}
// Register the bean to the container.
registerBean(repositoryBean);
afterBeanDiscovery.addBean(repositoryBean);
}
}
// Register the bean to the container.
registerBean(repositoryBean);
afterBeanDiscovery.addBean(repositoryBean);
}
}
/**
* Creates a {@link Bean}.
*
* @param <T> The type of the repository.
* @param repositoryType The class representing the repository.
* @param beanManager The BeanManager instance.
* @return The bean.
*/
private <T> CdiRepositoryBean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers,
BeanManager beanManager) {
Bean<Session> sessionBean = this.sessions.get(qualifiers);
/**
* Creates a {@link Bean}.
*
* @param <T> The type of the repository.
* @param repositoryType The class representing the repository.
* @param beanManager The BeanManager instance.
* @return The bean.
*/
private <T> CdiRepositoryBean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers,
BeanManager beanManager) {
Bean<Session> sessionBean = this.sessions.get(qualifiers);
if (sessionBean == null) {
throw new UnsatisfiedResolutionException(String.format(
"Unable to resolve a bean for '%s' with qualifiers %s.", Session.class.getName(), qualifiers));
}
if (sessionBean == null) {
throw new UnsatisfiedResolutionException(
String.format("Unable to resolve a bean for '%s' with qualifiers %s.", Session.class.getName(), qualifiers));
}
return new Neo4jCdiRepositoryBean<T>(sessionBean, qualifiers, repositoryType, beanManager,
getCustomImplementationDetector());
}
return new Neo4jCdiRepositoryBean<T>(sessionBean, qualifiers, repositoryType, beanManager,
getCustomImplementationDetector());
}
}

View File

@@ -13,7 +13,12 @@
package org.springframework.data.neo4j.repository.config;
import java.lang.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.ComponentScan;
@@ -37,93 +42,93 @@ import org.springframework.transaction.PlatformTransactionManager;
@Import(Neo4jRepositoriesRegistrar.class)
public @interface EnableNeo4jRepositories {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
* {@code @EnableExperimentalNeo4jRepositories("org.my.pkg")} instead of
* {@code @EnableExperimentalNeo4jRepositories(basePackages="org.my.pkg")}.
*/
String[] value() default {};
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
* {@code @EnableExperimentalNeo4jRepositories("org.my.pkg")} instead of
* {@code @EnableExperimentalNeo4jRepositories(basePackages="org.my.pkg")}.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*/
String[] basePackages() default {};
/**
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in
* each package that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in
* each package that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters.
*/
ComponentScan.Filter[] includeFilters() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters.
*/
ComponentScan.Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
ComponentScan.Filter[] excludeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
ComponentScan.Filter[] excludeFilters() default {};
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So
* for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning
* for {@code PersonRepositoryImpl}.
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So
* for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning
* for {@code PersonRepositoryImpl}.
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will default to
* {@code META-INFO/neo4j-named-queries.properties}.
*/
String namedQueriesLocation() default "";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will default to
* {@code META-INFO/neo4j-named-queries.properties}.
*/
String namedQueriesLocation() default "";
/**
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link org.springframework.data.repository.query.QueryLookupStrategy.Key#CREATE_IF_NOT_FOUND}.
*/
QueryLookupStrategy.Key queryLookupStrategy() default QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND;
/**
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link org.springframework.data.repository.query.QueryLookupStrategy.Key#CREATE_IF_NOT_FOUND}.
*/
QueryLookupStrategy.Key queryLookupStrategy() default QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND;
/**
* Returns the {@link org.springframework.beans.factory.FactoryBean} class to be used for each repository instance. Defaults to
* {@link Neo4jRepositoryFactoryBean}.
*/
Class<?> repositoryFactoryBeanClass() default Neo4jRepositoryFactoryBean.class;
/**
* Returns the {@link org.springframework.beans.factory.FactoryBean} class to be used for each repository instance.
* Defaults to {@link Neo4jRepositoryFactoryBean}.
*/
Class<?> repositoryFactoryBeanClass() default Neo4jRepositoryFactoryBean.class;
/**
* Configure the repository base class to be used to create repository proxies for this particular configuration.
*
* @return
*/
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
/**
* Configure the repository base class to be used to create repository proxies for this particular configuration.
*
* @return
*/
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
/**
* Configures the name of the {@link SessionFactory} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code sessionFactory}.
*/
String sessionFactoryRef() default "sessionFactory";
/**
* Configures the name of the {@link SessionFactory} bean definition to be used to create repositories discovered
* through this annotation. Defaults to {@code sessionFactory}.
*/
String sessionFactoryRef() default "sessionFactory";
/**
* Configures the name of the {@link PlatformTransactionManager} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code transactionManager}.
*/
String transactionManagerRef() default "transactionManager";
/**
* Configures the name of the {@link PlatformTransactionManager} bean definition to be used to create repositories
* discovered through this annotation. Defaults to {@code transactionManager}.
*/
String transactionManagerRef() default "transactionManager";
/**
* Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the
* repositories infrastructure.
*/
boolean considerNestedRepositories() default false;
/**
* Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the
* repositories infrastructure.
*/
boolean considerNestedRepositories() default false;
/**
* Configures whether to enable default transactions for Spring Data Neo4j repositories. Defaults to {@literal true}. If
* disabled, repositories must be used behind a facade that's configuring transactions (e.g. using Spring's annotation
* driven transaction facilities) or repository methods have to be used to demarcate transactions.
*
* @return whether to enable default transactions, defaults to {@literal true}.
*/
boolean enableDefaultTransactions() default true;
/**
* Configures whether to enable default transactions for Spring Data Neo4j repositories. Defaults to {@literal true}.
* If disabled, repositories must be used behind a facade that's configuring transactions (e.g. using Spring's
* annotation driven transaction facilities) or repository methods have to be used to demarcate transactions.
*
* @return whether to enable default transactions, defaults to {@literal true}.
*/
boolean enableDefaultTransactions() default true;
}

View File

@@ -13,7 +13,6 @@
package org.springframework.data.neo4j.repository.config;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
@@ -28,8 +27,8 @@ import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
*
* @author Mark Angrish
*/
class Neo4jMappingContextFactoryBean extends AbstractFactoryBean<Neo4jMappingContext> implements
ApplicationContextAware {
class Neo4jMappingContextFactoryBean extends AbstractFactoryBean<Neo4jMappingContext>
implements ApplicationContextAware {
private ListableBeanFactory beanFactory;
@@ -52,9 +51,9 @@ class Neo4jMappingContextFactoryBean extends AbstractFactoryBean<Neo4jMappingCon
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
*/
* (non-Javadoc)
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
*/
@Override
protected Neo4jMappingContext createInstance() throws Exception {

View File

@@ -13,11 +13,11 @@
package org.springframework.data.neo4j.repository.config;
import java.lang.annotation.Annotation;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import java.lang.annotation.Annotation;
/**
* @author Vince Bickers
* @author Mark Angrish

View File

@@ -83,7 +83,6 @@ public class Neo4jRepositoryConfigurationExtension extends RepositoryConfigurati
return MODULE_PREFIX;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingAnnotations()
@@ -175,7 +174,8 @@ public class Neo4jRepositoryConfigurationExtension extends RepositoryConfigurati
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SharedSessionCreator.class,
"createSharedSession");
builder.addConstructorArgReference(sessionFactoryBeanName == null ? DEFAULT_SESSION_FACTORY_BEAN_NAME : sessionFactoryBeanName);
builder.addConstructorArgReference(
sessionFactoryBeanName == null ? DEFAULT_SESSION_FACTORY_BEAN_NAME : sessionFactoryBeanName);
return builder.getBeanDefinition();

View File

@@ -13,6 +13,8 @@
package org.springframework.data.neo4j.repository.query;
import java.lang.reflect.Method;
import org.neo4j.ogm.session.Session;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.NamedQueries;
@@ -20,8 +22,6 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.RepositoryQuery;
import java.lang.reflect.Method;
/**
* @author Mark Angrish
* @author Luanne Misquitta
@@ -29,19 +29,19 @@ import java.lang.reflect.Method;
*/
public class GraphQueryLookupStrategy implements QueryLookupStrategy {
private final Session session;
private final Session session;
public GraphQueryLookupStrategy(Session session) {
this.session = session;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
*/
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
return new GraphQueryMethod(method, metadata, factory, session).createQuery();
}
public GraphQueryLookupStrategy(Session session) {
this.session = session;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
*/
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
return new GraphQueryMethod(method, metadata, factory, session).createQuery();
}
}

View File

@@ -36,131 +36,128 @@ import org.springframework.data.repository.query.RepositoryQuery;
*/
public class GraphQueryMethod extends QueryMethod {
private final Session session;
private final Method method;
private final Query queryAnnotation;
private final Integer queryDepthParamIndex;
private final Integer queryDepth;
private boolean staticDepth;
private final Session session;
private final Method method;
private final Query queryAnnotation;
private final Integer queryDepthParamIndex;
private final Integer queryDepth;
private boolean staticDepth;
public GraphQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory, Session session) {
super(method, metadata, factory);
this.method = method;
this.session = session;
this.queryAnnotation = method.getAnnotation(Query.class);
this.queryDepthParamIndex = getQueryDepthParamIndex(method);
this.queryDepth = getStaticQueryDepth(method);
if (queryDepth!=null && queryDepthParamIndex!=null) {
throw new IllegalArgumentException(method.getName() + " cannot have both a method @Depth and a parameter @Depth");
}
public GraphQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory, Session session) {
super(method, metadata, factory);
this.method = method;
this.session = session;
this.queryAnnotation = method.getAnnotation(Query.class);
this.queryDepthParamIndex = getQueryDepthParamIndex(method);
this.queryDepth = getStaticQueryDepth(method);
if (queryDepth != null && queryDepthParamIndex != null) {
throw new IllegalArgumentException(method.getName() + " cannot have both a method @Depth and a parameter @Depth");
}
}
}
public String getQuery() {
return queryAnnotation.value();
}
public String getQuery() {
return queryAnnotation.value();
}
public Method getMethod() {
return method;
}
public Method getMethod() {
return method;
}
@Override
public String getNamedQueryName() {
throw new UnsupportedOperationException("OGM does not currently support named queries.");
}
@Override
public String getNamedQueryName() {
throw new UnsupportedOperationException("OGM does not currently support named queries.");
}
/**
* @return The concrete, non-generic return type of this query method - i.e., the type to which graph database query results
* should be mapped
*/
public Class<?> resolveConcreteReturnType() {
Class<?> type = this.method.getReturnType();
Type genericType = this.method.getGenericReturnType();
/**
* @return The concrete, non-generic return type of this query method - i.e., the type to which graph database query
* results should be mapped
*/
public Class<?> resolveConcreteReturnType() {
Class<?> type = this.method.getReturnType();
Type genericType = this.method.getGenericReturnType();
if (Iterable.class.isAssignableFrom(type)) {
if (genericType instanceof ParameterizedType) {
ParameterizedType returnType = (ParameterizedType) genericType;
Type componentType = returnType.getActualTypeArguments()[0];
if (Iterable.class.isAssignableFrom(type)) {
if (genericType instanceof ParameterizedType) {
ParameterizedType returnType = (ParameterizedType) genericType;
Type componentType = returnType.getActualTypeArguments()[0];
if (componentType instanceof TypeVariable) {
return this.getDomainClass();
}
return componentType instanceof ParameterizedType ?
(Class<?>) ((ParameterizedType) componentType).getRawType() :
(Class<?>) componentType;
} else {
return Object.class;
}
}
if (componentType instanceof TypeVariable) {
return this.getDomainClass();
}
return componentType instanceof ParameterizedType ? (Class<?>) ((ParameterizedType) componentType).getRawType()
: (Class<?>) componentType;
} else {
return Object.class;
}
}
return type;
}
return type;
}
public RepositoryQuery createQuery() {
if (method.getAnnotation(Query.class) != null) {
if (resolveConcreteReturnType().isAnnotationPresent(QueryResult.class)) {
return new QueryResultGraphRepositoryQuery(this, session);
}
return new GraphRepositoryQuery(this, session);
}
return new DerivedGraphRepositoryQuery(this, session);
public RepositoryQuery createQuery() {
if (method.getAnnotation(Query.class) != null) {
if (resolveConcreteReturnType().isAnnotationPresent(QueryResult.class)) {
return new QueryResultGraphRepositoryQuery(this, session);
}
return new GraphRepositoryQuery(this, session);
}
return new DerivedGraphRepositoryQuery(this, session);
}
}
public Integer getQueryDepthParamIndex() {
return queryDepthParamIndex;
}
public Integer getQueryDepthParamIndex() {
return queryDepthParamIndex;
}
public Integer getQueryDepth() {
return queryDepth;
}
public Integer getQueryDepth() {
return queryDepth;
}
public boolean hasStaticDepth() {
return staticDepth;
}
public boolean hasStaticDepth() {
return staticDepth;
}
private Integer getQueryDepthParamIndex(Method method) {
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < annotations.length; i++) {
if (annotations[i].length > 0) {
for (Annotation annotation : annotations[i]) {
if (annotation.annotationType() == Depth.class) {
if (method.getParameterTypes()[i] == Integer.class || method.getParameterTypes()[i] == int.class) {
return i;
}
else {
throw new IllegalArgumentException("Depth parameter in " + method.getName() + " must be an integer");
}
}
}
}
}
/*
//Java 8 only
Parameter[] parameters = method.getParameters();
for (int i = 0; i < method.getParameterCount(); i++) {
if (parameters[i].isAnnotationPresent(Depth.class)) {
if (parameters[i].getType() == Integer.class || parameters[i].getType() == int.class) {
return i;
}
else {
throw new IllegalArgumentException("Depth parameter in " + method.getName() + " must be an integer");
}
}
}*/
return null;
}
private Integer getQueryDepthParamIndex(Method method) {
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < annotations.length; i++) {
if (annotations[i].length > 0) {
for (Annotation annotation : annotations[i]) {
if (annotation.annotationType() == Depth.class) {
if (method.getParameterTypes()[i] == Integer.class || method.getParameterTypes()[i] == int.class) {
return i;
} else {
throw new IllegalArgumentException("Depth parameter in " + method.getName() + " must be an integer");
}
}
}
}
}
/*
//Java 8 only
Parameter[] parameters = method.getParameters();
for (int i = 0; i < method.getParameterCount(); i++) {
if (parameters[i].isAnnotationPresent(Depth.class)) {
if (parameters[i].getType() == Integer.class || parameters[i].getType() == int.class) {
return i;
}
else {
throw new IllegalArgumentException("Depth parameter in " + method.getName() + " must be an integer");
}
}
}*/
return null;
}
private Integer getStaticQueryDepth(Method method) {
if (method.isAnnotationPresent(Depth.class)) {
staticDepth = true;
return method.getAnnotation(Depth.class).value();
}
return null;
}
private Integer getStaticQueryDepth(Method method) {
if (method.isAnnotationPresent(Depth.class)) {
staticDepth = true;
return method.getAnnotation(Depth.class).value();
}
return null;
}
public String getCountQueryString() {
return queryAnnotation != null ? queryAnnotation.countQuery() : null;
}
public String getCountQueryString() {
return queryAnnotation != null ? queryAnnotation.countQuery() : null;
}
}

View File

@@ -13,7 +13,6 @@
package org.springframework.data.neo4j.repository.query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -21,7 +20,10 @@ import java.util.Map;
import org.neo4j.ogm.model.QueryStatistics;
import org.neo4j.ogm.model.Result;
import org.neo4j.ogm.session.Session;
import org.springframework.data.domain.*;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.Parameters;
@@ -30,7 +32,6 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.util.StringUtils;
/**
* Specialisation of {@link RepositoryQuery} that handles mapping to object annotated with <code>&#064;Query</code>.
*
@@ -64,12 +65,11 @@ public class GraphRepositoryQuery implements RepositoryQuery {
ResultProcessor processor = graphQueryMethod.getResultProcessor();
Object result = execute(returnType, concreteType, getQueryString(), params, accessor);
return Result.class.equals(returnType) ? result :
processor.withDynamicProjection(accessor).processResult(result);
return Result.class.equals(returnType) ? result : processor.withDynamicProjection(accessor).processResult(result);
}
protected Object execute(Class<?> returnType, Class<?> concreteType, String cypherQuery,
Map<String, Object> queryParams, ParameterAccessor parameterAccessor) {
Map<String, Object> queryParams, ParameterAccessor parameterAccessor) {
Pageable pageable = parameterAccessor.getPageable();
Sort sort = parameterAccessor.getSort();
@@ -77,7 +77,7 @@ public class GraphRepositoryQuery implements RepositoryQuery {
sort = pageable.getSort();
}
if (sort != null) {
//Custom queries in the OGM do not support pageable
// Custom queries in the OGM do not support pageable
cypherQuery = addSorting(cypherQuery, sort);
}
@@ -106,7 +106,6 @@ public class GraphRepositoryQuery implements RepositoryQuery {
return getQueryMethod().getQuery();
}
protected Object createPage(GraphQueryMethod graphQueryMethod, List resultList, Pageable pageable, Long count) {
if (pageable == null) {
return graphQueryMethod.isPageQuery() ? new PageImpl(resultList) : new SliceImpl(resultList);
@@ -116,15 +115,15 @@ public class GraphRepositoryQuery implements RepositoryQuery {
currentTotal = count.intValue();
} else {
int pageOffset = pageable.getOffset();
currentTotal = pageOffset + resultList.size() + (resultList.size() == pageable.getPageSize() ? pageable.getPageSize() : 0);
currentTotal = pageOffset + resultList.size()
+ (resultList.size() == pageable.getPageSize() ? pageable.getPageSize() : 0);
}
int resultWindowSize = Math.min(resultList.size(), pageable.getPageSize());
boolean hasNext = resultWindowSize < resultList.size();
List resultListPage = resultList.subList(0, resultWindowSize);
return graphQueryMethod.isPageQuery() ?
new PageImpl(resultListPage, pageable, currentTotal) :
new SliceImpl(resultListPage, pageable, hasNext);
return graphQueryMethod.isPageQuery() ? new PageImpl(resultListPage, pageable, currentTotal)
: new SliceImpl(resultListPage, pageable, hasNext);
}
protected String addSorting(String baseQuery, Sort sort) {
@@ -140,7 +139,7 @@ public class GraphRepositoryQuery implements RepositoryQuery {
}
protected String addPaging(String cypherQuery, Map<String, Object> queryParams, int pageNumber, int pageSize) {
//Custom queries in the OGM do not support pageable
// Custom queries in the OGM do not support pageable
cypherQuery = formatBaseQuery(cypherQuery);
cypherQuery = cypherQuery + SKIP_LIMIT;
queryParams.put(SKIP, pageNumber * pageSize);
@@ -177,9 +176,9 @@ public class GraphRepositoryQuery implements RepositoryQuery {
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = methodParameters.getParameter(i);
//The parameter might be an entity, try to resolve its id
// The parameter might be an entity, try to resolve its id
Object parameterValue = session.resolveGraphIdFor(parameters[i]);
if (parameterValue == null) { //Either not an entity or not persisted
if (parameterValue == null) { // Either not an entity or not persisted
parameterValue = parameters[i];
}
@@ -192,7 +191,8 @@ public class GraphRepositoryQuery implements RepositoryQuery {
return params;
}
private Object mappedCollection(Class<?> concreteType, String cypherQuery, Map<String, Object> queryParams, Pageable pageable) {// Special method to handle SDN Iterable<Map<String, Object>> behaviour.
private Object mappedCollection(Class<?> concreteType, String cypherQuery, Map<String, Object> queryParams,
Pageable pageable) {// Special method to handle SDN Iterable<Map<String, Object>> behaviour.
// TODO: Do we really want this method in an OGM? It's a little too low level and/or doesn't really fit.
if (Map.class.isAssignableFrom(concreteType)) {
return session.query(cypherQuery, queryParams).queryResults();

View File

@@ -13,8 +13,7 @@
package org.springframework.data.neo4j.repository.query;
import static java.lang.reflect.Proxy.newProxyInstance;
import static java.lang.reflect.Proxy.*;
import java.util.ArrayList;
import java.util.Collection;
@@ -33,7 +32,8 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.ParameterAccessor;
/**
* Specialisation of {@link GraphRepositoryQuery} that handles mapping to objects annotated with <code>&#064;QueryResult</code>.
* Specialisation of {@link GraphRepositoryQuery} that handles mapping to objects annotated with
* <code>&#064;QueryResult</code>.
*
* @author Adam George
* @author Luanne Misquitta
@@ -53,7 +53,7 @@ public class QueryResultGraphRepositoryQuery extends GraphRepositoryQuery {
@Override
protected Object execute(Class<?> returnType, final Class<?> concreteReturnType, String cypherQuery,
Map<String, Object> queryParams, ParameterAccessor parameterAccessor) {
Map<String, Object> queryParams, ParameterAccessor parameterAccessor) {
Pageable pageable = parameterAccessor.getPageable();
Sort sort = parameterAccessor.getSort();
@@ -61,7 +61,7 @@ public class QueryResultGraphRepositoryQuery extends GraphRepositoryQuery {
sort = pageable.getSort();
}
if (sort != null) {
//Custom queries in the OGM do not support pageable
// Custom queries in the OGM do not support pageable
cypherQuery = addSorting(cypherQuery, sort);
}
@@ -78,7 +78,7 @@ public class QueryResultGraphRepositoryQuery extends GraphRepositoryQuery {
}
private Object mapToConcreteType(final Class<?> targetType, final String cypherQuery,
final Map<String, Object> queryParams, Pageable pageable) {
final Map<String, Object> queryParams, Pageable pageable) {
if (graphQueryMethod.isPageQuery() || graphQueryMethod.isSliceQuery()) {
final String query = addPaging(cypherQuery, queryParams, pageable.getPageNumber(), pageable.getPageSize());
@@ -90,7 +90,7 @@ public class QueryResultGraphRepositoryQuery extends GraphRepositoryQuery {
}
private Object mapToProxy(Class<?> targetType, String cypherQuery, Map<String, Object> queryParams,
Pageable pageable) {
Pageable pageable) {
if (graphQueryMethod.isPageQuery() || graphQueryMethod.isSliceQuery()) {
final String query = addPaging(cypherQuery, queryParams, pageable.getPageNumber(), pageable.getPageSize());
List<Object> objects = mappedProxyResults(targetType, this.session.query(query, queryParams));
@@ -100,7 +100,8 @@ public class QueryResultGraphRepositoryQuery extends GraphRepositoryQuery {
}
}
private List mappedConcreteResults(final Class<?> targetType, final String query, final Map<String, Object> queryParams) {
private List mappedConcreteResults(final Class<?> targetType, final String query,
final Map<String, Object> queryParams) {
return (List) this.session.doInTransaction(new GraphCallback<Collection<Object>>() {
@Override
public Collection<Object> apply(Request requestHandler, Transaction transaction, MetaData metaData) {
@@ -117,7 +118,7 @@ public class QueryResultGraphRepositoryQuery extends GraphRepositoryQuery {
private List mappedProxyResults(Class<?> targetType, Iterable<Map<String, Object>> queryResults) {
List<Object> resultObjects = new ArrayList<>();
Class<?>[] interfaces = new Class<?>[]{targetType};
Class<?>[] interfaces = new Class<?>[] { targetType };
for (Map<String, Object> map : queryResults) {
resultObjects.add(newProxyInstance(targetType.getClassLoader(), interfaces, new QueryResultProxy(map)));
}

View File

@@ -13,17 +13,17 @@
package org.springframework.data.neo4j.repository.query;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.session.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.session.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Method {@link InvocationHandler} used for proxy objects that implement arbitrary interfaces annotated with
* <code>&#064;QueryResult</code>.
@@ -32,41 +32,41 @@ import java.util.regex.Pattern;
*/
class QueryResultProxy implements InvocationHandler {
private static final Logger log = LoggerFactory.getLogger(QueryResultProxy.class);
private static final Logger log = LoggerFactory.getLogger(QueryResultProxy.class);
private static final Pattern beanGetterPattern = Pattern.compile("^(is|get)(\\w+)");
private static final Pattern beanGetterPattern = Pattern.compile("^(is|get)(\\w+)");
private final Map<String, ?> data;
private final Map<String, ?> data;
QueryResultProxy(Map<String, ?> queryResults) {
this.data = queryResults;
}
QueryResultProxy(Map<String, ?> queryResults) {
this.data = queryResults;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (isNotTraditionalGetter(method)) {
log.warn("QueryResult interface method " + method.getName()
+ " doesn't appear to be a getter and therefore may not return the correct result.");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (isNotTraditionalGetter(method)) {
log.warn("QueryResult interface method " + method.getName()
+ " doesn't appear to be a getter and therefore may not return the correct result.");
}
if (method.isAnnotationPresent(Property.class)) {
Property annotation = method.getAnnotation(Property.class);
return Utils.coerceTypes(method.getReturnType(), data.get(annotation.name()));
}
if (method.isAnnotationPresent(Property.class)) {
Property annotation = method.getAnnotation(Property.class);
return Utils.coerceTypes(method.getReturnType(), data.get(annotation.name()));
}
Matcher matcher = beanGetterPattern.matcher(method.getName());
if (matcher.matches()) {
String propertyKey = matcher.group(2);
propertyKey = propertyKey.substring(0, 1).toLowerCase().concat(propertyKey.substring(1));
return Utils.coerceTypes(method.getReturnType(),data.get(propertyKey));
}
Matcher matcher = beanGetterPattern.matcher(method.getName());
if (matcher.matches()) {
String propertyKey = matcher.group(2);
propertyKey = propertyKey.substring(0, 1).toLowerCase().concat(propertyKey.substring(1));
return Utils.coerceTypes(method.getReturnType(), data.get(propertyKey));
}
return Utils.coerceTypes(method.getReturnType(), data.get(method.getName()));
}
return Utils.coerceTypes(method.getReturnType(), data.get(method.getName()));
}
private boolean isNotTraditionalGetter(Method method) {
return method.getParameterTypes().length != 0 || Void.class.equals(method.getReturnType())
|| (!method.getName().startsWith("get") && !method.getName().startsWith("is"));
}
private boolean isNotTraditionalGetter(Method method) {
return method.getParameterTypes().length != 0 || Void.class.equals(method.getReturnType())
|| (!method.getName().startsWith("get") && !method.getName().startsWith("is"));
}
}

View File

@@ -12,11 +12,21 @@
*/
package org.springframework.data.neo4j.repository.query.derived;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.neo4j.ogm.cypher.BooleanOperator;
import org.neo4j.ogm.cypher.Filter;
import org.springframework.data.neo4j.repository.query.derived.builder.*;
import org.springframework.data.neo4j.repository.query.derived.builder.BetweenComparisonBuilder;
import org.springframework.data.neo4j.repository.query.derived.builder.BooleanComparisonBuilder;
import org.springframework.data.neo4j.repository.query.derived.builder.DistanceComparisonBuilder;
import org.springframework.data.neo4j.repository.query.derived.builder.ExistsFilterBuilder;
import org.springframework.data.neo4j.repository.query.derived.builder.FilterBuilder;
import org.springframework.data.neo4j.repository.query.derived.builder.IsNullFilterBuilder;
import org.springframework.data.neo4j.repository.query.derived.builder.PropertyComparisonBuilder;
import org.springframework.data.repository.query.parser.Part;
/**
@@ -28,64 +38,64 @@ import org.springframework.data.repository.query.parser.Part;
*/
public class CypherFinderQuery implements DerivedQueryDefinition {
private Class<?> entityType;
private Part basePart;
private List<FilterBuilder> filterBuilders = new ArrayList<>();
private Class<?> entityType;
private Part basePart;
private List<FilterBuilder> filterBuilders = new ArrayList<>();
CypherFinderQuery(Class<?> entityType, Part basePart) {
this.entityType = entityType;
this.basePart = basePart;
}
CypherFinderQuery(Class<?> entityType, Part basePart) {
this.entityType = entityType;
this.basePart = basePart;
}
@Override
public Part getBasePart() { //because the OR is handled in a weird way. Luanne, explain better
return basePart;
}
@Override
public Part getBasePart() { // because the OR is handled in a weird way. Luanne, explain better
return basePart;
}
@Override
public List<Filter> getFilters(Map<Integer, Object> params) {
@Override
public List<Filter> getFilters(Map<Integer, Object> params) {
// buiding a stack of parameter values, so that the builders can pull them
// according to their needs (zero, one or more parameters)
// avoids to manage a current parameter index state here.
Stack<Object> parametersStack = new Stack<>();
if (!params.isEmpty()) {
Integer maxParameterIndex = Collections.max(params.keySet());
for (int i = 0; i <= maxParameterIndex; i++) {
parametersStack.add(0, params.get(i));
}
}
// buiding a stack of parameter values, so that the builders can pull them
// according to their needs (zero, one or more parameters)
// avoids to manage a current parameter index state here.
Stack<Object> parametersStack = new Stack<>();
if (!params.isEmpty()) {
Integer maxParameterIndex = Collections.max(params.keySet());
for (int i = 0; i <= maxParameterIndex; i++) {
parametersStack.add(0, params.get(i));
}
}
List<Filter> filters = new ArrayList<>();
for (FilterBuilder filterBuilder : filterBuilders) {
filters.addAll(filterBuilder.build(parametersStack));
}
return filters;
}
List<Filter> filters = new ArrayList<>();
for (FilterBuilder filterBuilder : filterBuilders) {
filters.addAll(filterBuilder.build(parametersStack));
}
return filters;
}
@Override
public void addPart(Part part, BooleanOperator booleanOperator) {
@Override
public void addPart(Part part, BooleanOperator booleanOperator) {
FilterBuilder builder = builderForPart(part, booleanOperator);
filterBuilders.add(builder);
}
FilterBuilder builder = builderForPart(part, booleanOperator);
filterBuilders.add(builder);
}
private FilterBuilder builderForPart(Part part, BooleanOperator booleanOperator) {
switch (part.getType()) {
case NEAR:
return new DistanceComparisonBuilder(part, booleanOperator, entityType);
case BETWEEN:
return new BetweenComparisonBuilder(part, booleanOperator, entityType);
case IS_NULL:
case IS_NOT_NULL:
return new IsNullFilterBuilder(part, booleanOperator, entityType);
case EXISTS:
return new ExistsFilterBuilder(part, booleanOperator, entityType);
case TRUE:
case FALSE:
return new BooleanComparisonBuilder(part, booleanOperator, entityType);
default:
return new PropertyComparisonBuilder(part, booleanOperator, entityType);
}
}
private FilterBuilder builderForPart(Part part, BooleanOperator booleanOperator) {
switch (part.getType()) {
case NEAR:
return new DistanceComparisonBuilder(part, booleanOperator, entityType);
case BETWEEN:
return new BetweenComparisonBuilder(part, booleanOperator, entityType);
case IS_NULL:
case IS_NOT_NULL:
return new IsNullFilterBuilder(part, booleanOperator, entityType);
case EXISTS:
return new ExistsFilterBuilder(part, booleanOperator, entityType);
case TRUE:
case FALSE:
return new BooleanComparisonBuilder(part, booleanOperator, entityType);
default:
return new PropertyComparisonBuilder(part, booleanOperator, entityType);
}
}
}

View File

@@ -13,7 +13,11 @@
package org.springframework.data.neo4j.repository.query.derived;
import java.util.*;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.neo4j.ogm.cypher.Filters;
import org.neo4j.ogm.cypher.query.Pagination;
@@ -89,7 +93,7 @@ public class DerivedGraphRepositoryQuery implements RepositoryQuery {
}
return session.count(info.getJavaType(), filters);
} else {
throw new RuntimeException("Long is required as the return type of a Count query");
throw new RuntimeException("Long is required as the return type of a Count query");
}
}
@@ -175,11 +179,13 @@ public class DerivedGraphRepositoryQuery implements RepositoryQuery {
return graphQueryMethod;
}
private List queryResults(Class<?> concreteType, int queryDepth, Filters params, PagingAndSorting pagingAndSorting) {
private List queryResults(Class<?> concreteType, int queryDepth, Filters params,
PagingAndSorting pagingAndSorting) {
List resultList;
switch (pagingAndSorting.configuration()) {
case PagingAndSorting.PAGING_AND_SORTING:
resultList = (List) session.loadAll(concreteType, params, pagingAndSorting.sortOrder, pagingAndSorting.pagination, queryDepth);
resultList = (List) session.loadAll(concreteType, params, pagingAndSorting.sortOrder,
pagingAndSorting.pagination, queryDepth);
break;
case PagingAndSorting.PAGING_ONLY:
@@ -213,15 +219,14 @@ public class DerivedGraphRepositoryQuery implements RepositoryQuery {
}
}
@Override
public QueryMethod getQueryMethod() {
return graphQueryMethod;
}
/**
* Sets values from parameters supplied by the finder on {@link org.neo4j.ogm.cypher.Filter} built by the {@link GraphQueryMethod}
* Sets values from parameters supplied by the finder on {@link org.neo4j.ogm.cypher.Filter} built by the
* {@link GraphQueryMethod}
*
* @param parameters parameter values supplied by the finder method
* @return List of Parameter with values set
@@ -239,22 +244,19 @@ public class DerivedGraphRepositoryQuery implements RepositoryQuery {
return new Filters(queryDefinition.getFilters(params));
}
protected Object createPage(GraphQueryMethod graphQueryMethod, List resultList, Pageable pageable) {
if (pageable == null) {
return graphQueryMethod.isPageQuery() ? new PageImpl(resultList) : new SliceImpl(resultList);
}
int currentTotal = pageable.getOffset() + resultList.size() +
(resultList.size() == pageable.getPageSize() ? pageable.getPageSize() : 0);
int currentTotal = pageable.getOffset() + resultList.size()
+ (resultList.size() == pageable.getPageSize() ? pageable.getPageSize() : 0);
int resultWindowSize = Math.min(resultList.size(), pageable.getPageSize());
boolean hasNext = resultWindowSize < resultList.size();
List resultListPage = resultList.subList(0, resultWindowSize);
return graphQueryMethod.isPageQuery() ?
new PageImpl(resultListPage, pageable, currentTotal) :
new SliceImpl(resultListPage, pageable, hasNext);
return graphQueryMethod.isPageQuery() ? new PageImpl(resultListPage, pageable, currentTotal)
: new SliceImpl(resultListPage, pageable, hasNext);
}
private SortOrder convert(Sort sort) {
@@ -290,7 +292,9 @@ public class DerivedGraphRepositoryQuery implements RepositoryQuery {
if (graphQueryMethod.isPageQuery() || graphQueryMethod.isSliceQuery()) {
if (graphQueryMethod.isSliceQuery()) {
pagination = new Pagination(pageable.getPageNumber(), pageable.getPageSize() + 1);
pagination.setOffset(pageable.getPageNumber() * pageable.getPageSize()); //For a slice, need one extra result to determine if there is a next page
pagination.setOffset(pageable.getPageNumber() * pageable.getPageSize()); // For a slice, need one extra result
// to determine if there is a next
// page
} else {
pagination = new Pagination(pageable.getPageNumber(), pageable.getPageSize());
}

View File

@@ -31,6 +31,7 @@ public class DerivedQueryBuilder {
/**
* Add a part as a parameter to the graph query.
*
* @param part the Part to be added
* @param booleanOperator the {@link BooleanOperator} to be used when appending the parameter to the query.
*/
@@ -40,6 +41,7 @@ public class DerivedQueryBuilder {
/**
* Add criteria from an intermediate builder to the query
*
* @param fromBuilder the intermediate builder
* @param booleanOperator the {@link BooleanOperator} to be used when appending the criteria to the query
*/
@@ -49,6 +51,7 @@ public class DerivedQueryBuilder {
/**
* Builds the final query
*
* @return the final query
*/
public DerivedQueryDefinition buildQuery() {

View File

@@ -11,17 +11,16 @@
*
*/
package org.springframework.data.neo4j.repository.query.derived;
import java.util.Iterator;
import org.neo4j.ogm.cypher.BooleanOperator;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
import java.util.Iterator;
/**
* An {@link AbstractQueryCreator} that builds a graph query.
*

View File

@@ -21,9 +21,8 @@ import org.neo4j.ogm.cypher.Filter;
import org.springframework.data.repository.query.parser.Part;
/**
* The graph query created based on a derived query.
* The graph query created based on a derived query. /**
*
/**
* @author Luanne Misquitta
* @author Nicolas Mervaillie
*/
@@ -31,19 +30,22 @@ public interface DerivedQueryDefinition {
/**
* Add a part as a parameter to the graph query.
* @param part the Part to be added
*
* @param part the Part to be added
* @param booleanOperator the {@link BooleanOperator} to be used when appending the parameter to the query.
*/
void addPart(Part part, BooleanOperator booleanOperator);
/**
* Get the base part i.e. the first parameter of the graph query.
*
* @return Part representing the base of the query.
*/
Part getBasePart();
/**
* Gets all cypher filters for this query
*
* @return The OGM filters with bound parameter values
*/
List<Filter> getFilters(Map<Integer, Object> params);

View File

@@ -11,7 +11,6 @@
*
*/
package org.springframework.data.neo4j.repository.query.derived.builder;
import static org.springframework.data.repository.query.parser.Part.Type.*;

View File

@@ -11,7 +11,6 @@
*
*/
package org.springframework.data.neo4j.repository.query.derived.builder;
import java.util.Collections;
@@ -54,7 +53,8 @@ public class DistanceComparisonBuilder extends FilterBuilder {
distance = (Distance) secondArg;
point = (Point) firstArg;
} else {
throw new IllegalArgumentException("findNear requires an argument of type Distance and an argument of type Point");
throw new IllegalArgumentException(
"findNear requires an argument of type Distance and an argument of type Point");
}
double meters;
@@ -66,7 +66,8 @@ public class DistanceComparisonBuilder extends FilterBuilder {
meters = distance.getValue();
}
DistanceFromPoint distanceFromPoint = new DistanceFromPoint(point.getX(), point.getY(), distance.getValue() * meters);
DistanceFromPoint distanceFromPoint = new DistanceFromPoint(point.getX(), point.getY(),
distance.getValue() * meters);
DistanceComparison distanceComparison = new DistanceComparison(distanceFromPoint);
Filter filter = new Filter();

View File

@@ -1,6 +1,5 @@
package org.springframework.data.neo4j.repository.query.derived.builder;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

View File

@@ -11,7 +11,6 @@
*
*/
package org.springframework.data.neo4j.repository.query.derived.builder;
import static org.springframework.data.repository.query.parser.Part.Type.*;
@@ -31,21 +30,21 @@ import org.springframework.data.repository.query.parser.Part;
*/
public class IsNullFilterBuilder extends FilterBuilder {
public IsNullFilterBuilder(Part part, BooleanOperator booleanOperator, Class<?> entityType) {
super(part, booleanOperator, entityType);
}
public IsNullFilterBuilder(Part part, BooleanOperator booleanOperator, Class<?> entityType) {
super(part, booleanOperator, entityType);
}
@Override
public List<Filter> build(Stack<Object> params) {
Filter filter = new Filter();
filter.setPropertyName(propertyName());
filter.setOwnerEntityType(entityType);
filter.setBooleanOperator(booleanOperator);
filter.setNegated(isNegated() || part.getType() == IS_NOT_NULL);
filter.setComparisonOperator(ComparisonOperator.IS_NULL);
setNestedAttributes(part, filter);
@Override
public List<Filter> build(Stack<Object> params) {
Filter filter = new Filter();
filter.setPropertyName(propertyName());
filter.setOwnerEntityType(entityType);
filter.setBooleanOperator(booleanOperator);
filter.setNegated(isNegated() || part.getType() == IS_NOT_NULL);
filter.setComparisonOperator(ComparisonOperator.IS_NULL);
setNestedAttributes(part, filter);
return Collections.singletonList(filter);
}
return Collections.singletonList(filter);
}
}

View File

@@ -47,7 +47,6 @@ public class PropertyComparisonBuilder extends FilterBuilder {
return Collections.singletonList(filter);
}
private ComparisonOperator convertToComparisonOperator(Part.Type type) {
switch (type) {
case AFTER:

View File

@@ -13,47 +13,47 @@
package org.springframework.data.neo4j.repository.support;
import java.io.Serializable;
import org.neo4j.ogm.MetaData;
import org.neo4j.ogm.entity.io.EntityAccessManager;
import org.neo4j.ogm.metadata.ClassInfo;
import org.neo4j.ogm.metadata.FieldInfo;
import org.springframework.data.repository.core.support.AbstractEntityInformation;
import java.io.Serializable;
/**
* @author Mark Angrish
*/
public class GraphEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID> {
private final MetaData metaData;
private final MetaData metaData;
public GraphEntityInformation(MetaData metaData, Class<T> type) {
super(type);
this.metaData = metaData;
}
public GraphEntityInformation(MetaData metaData, Class<T> type) {
super(type);
this.metaData = metaData;
}
@Override
public ID getId(T entity) {
final ClassInfo classInfo = metaData.classInfo(getJavaType().getName());
final FieldInfo primaryIndex = classInfo.primaryIndexField();
@Override
public ID getId(T entity) {
final ClassInfo classInfo = metaData.classInfo(getJavaType().getName());
final FieldInfo primaryIndex = classInfo.primaryIndexField();
if (primaryIndex != null) {
return (ID) EntityAccessManager.getPropertyReader(classInfo, primaryIndex.getName()).readProperty(entity);
}
else {
return (ID) EntityAccessManager.getPropertyReader(classInfo, classInfo.identityField().getName()).readProperty(entity);
}
}
if (primaryIndex != null) {
return (ID) EntityAccessManager.getPropertyReader(classInfo, primaryIndex.getName()).readProperty(entity);
} else {
return (ID) EntityAccessManager.getPropertyReader(classInfo, classInfo.identityField().getName())
.readProperty(entity);
}
}
@Override
public Class<ID> getIdType() {
final FieldInfo primaryIndex = metaData.classInfo(getJavaType().getName()).primaryIndexField();
@Override
public Class<ID> getIdType() {
final FieldInfo primaryIndex = metaData.classInfo(getJavaType().getName()).primaryIndexField();
if (primaryIndex != null) {
return (Class<ID>) primaryIndex.convertedType();
}
return (Class<ID>) Long.class;
}
if (primaryIndex != null) {
return (Class<ID>) primaryIndex.convertedType();
}
return (Class<ID>) Long.class;
}
}

View File

@@ -24,9 +24,9 @@ import org.springframework.data.neo4j.transaction.SessionFactoryUtils;
*/
public class Neo4jPersistenceExceptionTranslator implements PersistenceExceptionTranslator {
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return SessionFactoryUtils.convertOgmAccessException(ex);
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return SessionFactoryUtils.convertOgmAccessException(ex);
}
}

View File

@@ -56,7 +56,7 @@ public class Neo4jRepositoryFactory extends RepositoryFactorySupport {
public <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> type) {
Assert.notNull(type, "Domain class must not be null!");
Assert.notNull(session, "Session must not be null!");
return new GraphEntityInformation(((Neo4jSession)session).metaData(), type);
return new GraphEntityInformation(((Neo4jSession) session).metaData(), type);
}
@Override
@@ -71,7 +71,7 @@ public class Neo4jRepositoryFactory extends RepositoryFactorySupport {
@Override
protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key,
EvaluationContextProvider evaluationContextProvider) {
EvaluationContextProvider evaluationContextProvider) {
return new GraphQueryLookupStrategy(session);
}
}

View File

@@ -23,7 +23,6 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.util.Assert;
/**
* Special adapter for Springs {@link org.springframework.beans.factory.FactoryBean} interface to allow easy setup of
* repository factories via Spring configuration.
@@ -33,13 +32,14 @@ import org.springframework.util.Assert;
* @author Luanne Misquitta
* @author Mark Angrish
*/
public class Neo4jRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {
public class Neo4jRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {
private Session session;
/**
* Creates a new {@link Neo4jRepositoryFactoryBean} for the given repository interface.
*
*
* @param repositoryInterface must not be {@literal null}.
*/
public Neo4jRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
@@ -81,5 +81,3 @@ public class Neo4jRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
return new Neo4jRepositoryFactory(session);
}
}

View File

@@ -18,10 +18,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.neo4j.ogm.MetaData;
import org.neo4j.ogm.cypher.query.Pagination;
import org.neo4j.ogm.cypher.query.SortOrder;
import org.neo4j.ogm.session.Neo4jSession;
import org.neo4j.ogm.session.Session;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -37,7 +35,6 @@ import org.springframework.util.Assert;
* you a more sophisticated interface than the plain {@link Session} .
*
* @param <T> the type of the entity to handle
*
* @author Vince Bickers
* @author Luanne Misquitta
* @author Mark Angrish
@@ -199,7 +196,8 @@ public class SimpleNeo4jRepository<T, ID extends Serializable> implements Neo4jR
@Override
public Page<T> findAll(Pageable pageable, int depth) {
Collection<T> data = session.loadAll(clazz, convert(pageable.getSort()), new Pagination(pageable.getPageNumber(), pageable.getPageSize()), depth);
Collection<T> data = session.loadAll(clazz, convert(pageable.getSort()),
new Pagination(pageable.getPageNumber(), pageable.getPageSize()), depth);
return updatePage(pageable, new ArrayList<T>(data));
}

View File

@@ -15,10 +15,9 @@ package org.springframework.data.neo4j.template;
import org.neo4j.ogm.session.Session;
/**
* Callback interface for Neo4j OGM code. To be used with {@link Neo4jTemplate}'s
* execution methods, often as anonymous classes within a method implementation.
* A typical implementation will call {@code Session.load/find/update} to perform
* some operations on persistent objects.
* Callback interface for Neo4j OGM code. To be used with {@link Neo4jTemplate}'s execution methods, often as anonymous
* classes within a method implementation. A typical implementation will call {@code Session.load/find/update} to
* perform some operations on persistent objects.
*
* @author Juergen Hoeller
* @see Neo4jTemplate
@@ -29,13 +28,12 @@ import org.neo4j.ogm.session.Session;
public interface Neo4jCallback<T> {
/**
* Gets called by {@code Neo4jTemplate.doExecute} with an active
* OGM {@code Session}. Does not need to care about activating
* or closing the {@code Session}, or handling transactions.
* <p>Allows for returning a result object created within the callback,
* i.e. a domain object or a collection of domain objects.
* A thrown custom RuntimeException is treated as an application exception:
* It gets propagated to the caller of the template.
* Gets called by {@code Neo4jTemplate.doExecute} with an active OGM {@code Session}. Does not need to care about
* activating or closing the {@code Session}, or handling transactions.
* <p>
* Allows for returning a result object created within the callback, i.e. a domain object or a collection of domain
* objects. A thrown custom RuntimeException is treated as an application exception: It gets propagated to the caller
* of the template.
*
* @param session active Neo4j session
* @return a result object, or {@code null} if none

View File

@@ -13,6 +13,8 @@
package org.springframework.data.neo4j.template;
import java.util.Collection;
import java.util.Map;
import org.neo4j.ogm.cypher.Filter;
import org.neo4j.ogm.cypher.Filters;
@@ -26,416 +28,427 @@ import org.neo4j.ogm.session.Session;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Map;
/**
* Spring Data operations interface, implemented by {@link Neo4jTemplate}, that provides the API for using
* the persistence framework in a more direct way as an alternative to the repositories.
* Spring Data operations interface, implemented by {@link Neo4jTemplate}, that provides the API for using the
* persistence framework in a more direct way as an alternative to the repositories.
*
* @author Adam George
* @author Luanne Misquitta
* @author Mark Angrish
*
* @deprecated Use {@link org.neo4j.ogm.session.Session}
*/
@Repository
@Deprecated
public interface Neo4jOperations {
/**
* Execute the action specified by the given action object within a
* {@link Session}.
* <p>Application exceptions thrown by the action object get propagated
* to the caller (can only be unchecked). OGM exceptions are
* transformed into appropriate DAO ones. Allows for returning a result
* object, that is a domain object or a collection of domain objects.
* <p>Note: Callback code is not supposed to handle transactions itself!
* Use an appropriate transaction manager like
* {@link org.springframework.data.neo4j.transaction.Neo4jTransactionManager}. Generally, callback code must not
* touch any {@code Session} lifecycle methods, like close,
* disconnect, or reconnect, to let the template do its work.
* @param action callback object that specifies the OGM action
* @return a result object returned by the action, or {@code null}
* @see Session
*/
<T> T execute(Neo4jCallback<T> action) throws DataAccessException;
/**
* Loads an entity of type T that matches the specified ID to the default depth.
*
* @param type The type of entity to load
* @param id The ID of the node or relationship to match
* @return The instance of T loaded from the database that matches the specified ID or <code>null</code> if no match is found
*/
<T> T load(Class<T> type, Long id);
/**
* Loads an entity of type T that matches the specified ID to the given depth.
*
* @param type The type of entity to load
* @param id The ID of the node or relationship to match
* @param depth The maximum number of relationships away from the identified object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return The instance of T loaded from the database that matches the specified ID or <code>null</code> if no match is found
*/
<T> T load(Class<T> type, Long id, int depth);
/**
* Retrieves all the entities of the given class in the database hydrated to the default depth.
*
* @param type The type of entity to return.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth.
*
* @param type The type of entity to return.
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, int depth);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth, with Sorting.
*
* @param type The type of entity to return.
* @param sortOrder The SortOrder to be applied
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, SortOrder sortOrder, int depth);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth, with Sorting and Pagination.
*
* @param type The type of entity to return.
* @param sortOrder The SortOrder to be applied
* @param pagination The Pagination to be applied
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, SortOrder sortOrder, Pagination pagination, int depth);
/**
* Reloads all of the entities which match IDs in the given {@link Collection} to the specified depth. Of course, this will
* only work for persistent objects (i.e., those with a non-null <code>@GraphId</code> field).
*
* @param type The type of entity to return.
* @param ids The IDs of objects to re-hydrate
* @param depth The depth to which the objects should be hydrated
* @return A new {@link Collection} of entities matching those in the given collection hydrated to the given depth
*/
<T> Collection<T> loadAll(Class<T> type, Collection<Long> ids, int depth);
/**
* Reloads all of the entities in the given {@link Collection} to the specified depth. Of course, this will
* only work for persistent objects (i.e., those with a non-null <code>@GraphId</code> field).
*
* @param objects The objects to re-hydrate
* @param depth The depth to which the objects should be hydrated
* @return A new {@link Collection} of entities matching those in the given collection hydrated to the given depth
*/
<T> Collection<T> loadAll(Collection<T> objects, int depth);
/**
* Reloads all of the entities in the given {@link Collection} to the specified depth, sorted by the sprcified SortOrder Of course, this will
* only work for persistent objects (i.e., those with a non-null <code>@GraphId</code> field).
*
* @param ids The IDs of objects to re-hydrate
* @param sortOrder The SortOrder to be used
* @param depth The depth to which the objects should be hydrated
* @return A new {@link Collection} of entities matching those in the given collection hydrated to the given depth
*/
<T> Collection<T> loadAll(Class<T> type, Collection<Long> ids, SortOrder sortOrder, int depth);
/**
* Retrieves all the entities of the given class in the database hydrated to the default depth conforming to the specified
* filter criteria.
*
* @param type The type of entity to return.
* @param filter The filter to constrain entities with.
* @return A {@link Collection} containing all matching instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, Filter filter);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth, with Pagination.
*
* @param type The type of entity to return.
* @param pagination The Pagination to be applied
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, Pagination pagination, int depth);
/**
* Retrieves all the entities of the given class in the database hydrated to the default depth conforming to the specified
* filter criteria.
*
* @param type The type of entity to return.
* @param filter The filter to constrain entities with.
* @param depth The depth to which the objects should be hydrated
* @return A {@link Collection} containing all matching instances of the given type in the database or an empty collection if none
* are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, Filter filter, int depth);
/**
* Retrieves the entity of the specified type that contains a property matching the given name with the given value.
* This method assumes that the requested property/value combination will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to
* be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @return The instance of T corresponding to the entity that matches the given property, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue);
/**
* Retrieves the entity of the specified type that contains a property matching the given name with the given value.
* This method assumes that the requested property/value combination will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to
* be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return The instance of T corresponding to the entity that matches the given property, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue, int depth);
/**
* Retrieves all the entities of the specified type that contain a property matching the given name with the given value.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @return A {@link Collection} containing all the entities that match the given property or an empty {@link Collection} if
* there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperty(Class<T> type, String propertyName, Object propertyValue);
/**
* Retrieves all the entities of the specified type that contain a property matching the given name with the given value.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all the entities that match the given property or an empty {@link Collection} if
* there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperty(Class<T> type, String propertyName, Object propertyValue, int depth);
/**
* Retrieves the entity of the specified type that contains properties matching the ones supplied with given name and value.
* This method assumes that the requested property/value combinations will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to
* be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @return The instance of T corresponding to the entity that matches the given properties, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperties(Class<T> type, Filters parameters);
/**
* Retrieves the entity of the specified type that contains properties matching the ones supplied with given name and value.
* This method assumes that the requested property/value combinations will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to
* be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return The instance of T corresponding to the entity that matches the given properties, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperties(Class<T> type, Filters parameters, int depth);
/**
* Retrieves all the entities of the specified type that contain a properties matching the ones supplied with given name and value.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @return A {@link Collection} containing all the entities that match the given properties or an empty {@link Collection} if
* there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters);
/**
* Retrieves all the entities of the specified type that contain a properties matching the ones supplied with given name and value.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all the entities that match the given properties or an empty {@link Collection} if
* there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters, int depth);
/**
* Saves the specified entity in the graph database. If the entity is currently transient then the persistent version of
* the entity will be returned, containing its new graph ID.
*
* @param entity The entity to save
* @return The saved entity
*/
<T> T save(T entity);
/**
* Saves the specified entity in the graph database to a custom depth. If the entity is currently transient then the persistent version of
* the entity will be returned, containing its new graph ID.
*
* @param entity The entity to save
* @param depth The maximum number of relationships away from the entity to follow when saving related entities.
* A value of 0 just saves the object's properties and no related entities. A value of -1 implies no depth limit.
* @return The saved entity
*/
<T> T save(T entity, int depth);
/**
* Removes the given node or relationship entity from the graph. The entity is first removed
* from all indexes and then deleted.
*
* @param entity The entity to delete
*/
void delete(Object entity);
/**
* Execute the action specified by the given action object within a {@link Session}.
* <p>
* Application exceptions thrown by the action object get propagated to the caller (can only be unchecked). OGM
* exceptions are transformed into appropriate DAO ones. Allows for returning a result object, that is a domain object
* or a collection of domain objects.
* <p>
* Note: Callback code is not supposed to handle transactions itself! Use an appropriate transaction manager like
* {@link org.springframework.data.neo4j.transaction.Neo4jTransactionManager}. Generally, callback code must not touch
* any {@code Session} lifecycle methods, like close, disconnect, or reconnect, to let the template do its work.
*
* @param action callback object that specifies the OGM action
* @return a result object returned by the action, or {@code null}
* @see Session
*/
<T> T execute(Neo4jCallback<T> action) throws DataAccessException;
/**
* Removes all nodes or relationship entities of a specific type from the graph.
* @param type the type of entity to delete
*/
<T> void deleteAll(Class<T> type);
* Loads an entity of type T that matches the specified ID to the default depth.
*
* @param type The type of entity to load
* @param id The ID of the node or relationship to match
* @return The instance of T loaded from the database that matches the specified ID or <code>null</code> if no match
* is found
*/
<T> T load(Class<T> type, Long id);
/**
* Removes all mapping information from the current session
*/
void clear();
/**
* Loads an entity of type T that matches the specified ID to the given depth.
*
* @param type The type of entity to load
* @param id The ID of the node or relationship to match
* @param depth The maximum number of relationships away from the identified object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return The instance of T loaded from the database that matches the specified ID or <code>null</code> if no match
* is found
*/
<T> T load(Class<T> type, Long id, int depth);
/**
* Executes the specified Cypher query with the given parameters against the underlying Neo4j database and returns the
* row-based result in the form of an {@link Iterable} of {@link Map}s.
* <p>
* Each of the resultant maps corresponds to a "row" in the result set and the key set in each map contains all the names
* contained in the <code>RETURN</code> clause of the given query.
* </p>
*
* @param cypherQuery The Cypher query to execute
* @param params The parameter to merge into the cypher query or an empty {@link Map} if the given query isn't parameterised
* @return A {@link Query} containing an {@link Iterable} map representing query results and {@link QueryStatistics} if applicable.
* @throws RuntimeException if the given query is not a valid Cypherquery
*/
Result query(String cypherQuery, Map<String, ?> params);
/**
* Retrieves all the entities of the given class in the database hydrated to the default depth.
*
* @param type The type of entity to return.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if
* none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type);
/**
* Runs the specified Cypher query with the given parameters against the underlying Neo4j database and returns the result
* marshalled as an object of the requested type.
*
* @param entityType The {@link Class} denoting the type of entity to return
* @param cypherQuery The Cypher query to execute
* @param parameters The parameter to merge into the Cypher query or an empty {@link Map} if the query's not parameterised
* @return An instance of T that corresponds to the entity found by executing the query or <code>null</code> if nothing is
* found by the query
* @throws RuntimeException If more than one result is returned or there's an issue executing the query
*/
<T> T queryForObject(Class<T> entityType, String cypherQuery, Map<String, ?> parameters);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth.
*
* @param type The type of entity to return.
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if
* none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, int depth);
/**
* Runs the specified Cypher query with the given parameters against the underlying Neo4j database and returns the result
* marshalled as a group of objects of the requested type.
*
* @param entityType The {@link Class} denoting the type of entity to return
* @param cypherQuery The Cypher query to execute
* @param parameters The parameter to merge into the Cypher query or an empty {@link Map} if the query's not parameterised
* @return An {@link Iterable} over the entities found by executing the query or an empty <code>Iterable</code> if nothing
* is found by the query, never <code>null</code>
* @throws RuntimeException If there's an issue executing the query
*/
<T> Iterable<T> queryForObjects(Class<T> entityType, String cypherQuery, Map<String, ?> parameters);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth, with Sorting.
*
* @param type The type of entity to return.
* @param sortOrder The SortOrder to be applied
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if
* none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, SortOrder sortOrder, int depth);
/**
* Given a cypher statement this method will return a {@link Query} object containing a collection of Map's which represent Neo4j
* objects as properties, along with query statistics if applicable.
*
* Each element of the query result is a map which you can access by the name of the returned field
*
* TODO: Are we going to use the neo4jOperations conversion method to cast the value object to its proper class?
*
* @param cypher The parametrisable cypher to execute.
* @param parameters Any parameters to attach to the cypher.
* @param readOnly true if the query is readOnly, false otherwise
*
* @return A {@link Query} of {@link Iterable}s with each entry representing a neo4j object's properties.
*/
Result query(String cypher, Map<String, ?> parameters, boolean readOnly);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth, with Sorting and
* Pagination.
*
* @param type The type of entity to return.
* @param sortOrder The SortOrder to be applied
* @param pagination The Pagination to be applied
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if
* none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, SortOrder sortOrder, Pagination pagination, int depth);
/**
* Provides the instance count for the given <em>node</em> entity type. This method is also provided by the
* corresponding repository.
*
* @param entityClass The {@link Class} representing the type of node entity to count
* @return The number of entities in the database of the given type
*/
long count(Class<?> entityClass);
/**
* Reloads all of the entities which match IDs in the given {@link Collection} to the specified depth. Of course, this
* will only work for persistent objects (i.e., those with a non-null <code>@GraphId</code> field).
*
* @param type The type of entity to return.
* @param ids The IDs of objects to re-hydrate
* @param depth The depth to which the objects should be hydrated
* @return A new {@link Collection} of entities matching those in the given collection hydrated to the given depth
*/
<T> Collection<T> loadAll(Class<T> type, Collection<Long> ids, int depth);
/**
* Reloads all of the entities in the given {@link Collection} to the specified depth. Of course, this will only work
* for persistent objects (i.e., those with a non-null <code>@GraphId</code> field).
*
* @param objects The objects to re-hydrate
* @param depth The depth to which the objects should be hydrated
* @return A new {@link Collection} of entities matching those in the given collection hydrated to the given depth
*/
<T> Collection<T> loadAll(Collection<T> objects, int depth);
// /**
// * Issue a single Cypher update operation (such as a <tt>CREATE</tt>, <tt>MERGE</tt> or <tt>DELETE</tt> statement).
// *
// * @deprecated Use {@link Neo4jOperations}.query() to return both results as well as query statistics.
// * @param cypherQuery The Cypher query to execute
// * @return {@link QueryStatistics} representing statistics about graph modifications as a result of the cypher execution.
// */
// @Deprecated
// QueryStatistics execute(String cypherQuery);
/**
* Reloads all of the entities in the given {@link Collection} to the specified depth, sorted by the sprcified
* SortOrder Of course, this will only work for persistent objects (i.e., those with a non-null <code>@GraphId</code>
* field).
*
* @param ids The IDs of objects to re-hydrate
* @param sortOrder The SortOrder to be used
* @param depth The depth to which the objects should be hydrated
* @return A new {@link Collection} of entities matching those in the given collection hydrated to the given depth
*/
<T> Collection<T> loadAll(Class<T> type, Collection<Long> ids, SortOrder sortOrder, int depth);
// /**
// * Allows a cypher statement with a modification statement to be executed.
// *
// * <p>Parameters may be scalars or domain objects themselves.</p>
// * @deprecated Use {@link Neo4jOperations}.query() to return both results as well as query statistics.
// * @param cypher The parametrisable cypher to execute.
// * @param parameters Any parameters to attach to the cypher. These may be domain objects or scalars. Note that
// * if a complex domain object is provided only the properties of that object will be set.
// * If relationships of a provided object also need to be set then the cypher should reflect this
// * and further domain object parameters provided.
// *
// * @return {@link QueryStatistics} representing statistics about graph modifications as a result of the cypher execution.
// */
// @Deprecated
// QueryStatistics execute(String cypher, Map<String, Object> parameters);
/**
* Retrieves all the entities of the given class in the database hydrated to the default depth conforming to the
* specified filter criteria.
*
* @param type The type of entity to return.
* @param filter The filter to constrain entities with.
* @return A {@link Collection} containing all matching instances of the given type in the database or an empty
* collection if none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, Filter filter);
/**
* Retrieves all the entities of the given class in the database hydrated to the specified depth, with Pagination.
*
* @param type The type of entity to return.
* @param pagination The Pagination to be applied
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return A {@link Collection} containing all instances of the given type in the database or an empty collection if
* none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, Pagination pagination, int depth);
/**
* Retrieves all the entities of the given class in the database hydrated to the default depth conforming to the
* specified filter criteria.
*
* @param type The type of entity to return.
* @param filter The filter to constrain entities with.
* @param depth The depth to which the objects should be hydrated
* @return A {@link Collection} containing all matching instances of the given type in the database or an empty
* collection if none are found, never <code>null</code>
*/
<T> Collection<T> loadAll(Class<T> type, Filter filter, int depth);
/**
* Retrieves the entity of the specified type that contains a property matching the given name with the given value.
* This method assumes that the requested property/value combination will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to be
* returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @return The instance of T corresponding to the entity that matches the given property, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue);
/**
* Retrieves the entity of the specified type that contains a property matching the given name with the given value.
* This method assumes that the requested property/value combination will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to be
* returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return The instance of T corresponding to the entity that matches the given property, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue, int depth);
/**
* Retrieves all the entities of the specified type that contain a property matching the given name with the given
* value.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @return A {@link Collection} containing all the entities that match the given property or an empty
* {@link Collection} if there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperty(Class<T> type, String propertyName, Object propertyValue);
/**
* Retrieves all the entities of the specified type that contain a property matching the given name with the given
* value.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return A {@link Collection} containing all the entities that match the given property or an empty
* {@link Collection} if there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperty(Class<T> type, String propertyName, Object propertyValue, int depth);
/**
* Retrieves the entity of the specified type that contains properties matching the ones supplied with given name and
* value. This method assumes that the requested property/value combinations will be unique for all entities of this
* type in the database and will throw an exception unless exactly one result is found. If several entities are
* expected to be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @return The instance of T corresponding to the entity that matches the given properties, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperties(Class<T> type, Filters parameters);
/**
* Retrieves the entity of the specified type that contains properties matching the ones supplied with given name and
* value. This method assumes that the requested property/value combinations will be unique for all entities of this
* type in the database and will throw an exception unless exactly one result is found. If several entities are
* expected to be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return The instance of T corresponding to the entity that matches the given properties, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperties(Class<T> type, Filters parameters, int depth);
/**
* Retrieves all the entities of the specified type that contain a properties matching the ones supplied with given
* name and value.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @return A {@link Collection} containing all the entities that match the given properties or an empty
* {@link Collection} if there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters);
/**
* Retrieves all the entities of the specified type that contain a properties matching the ones supplied with given
* name and value.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @param depth The maximum number of relationships away from each loaded object to follow when loading related
* entities. A value of 0 just loads the object's properties and no related entities. A value of -1 implies
* no depth limit.
* @return A {@link Collection} containing all the entities that match the given properties or an empty
* {@link Collection} if there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters, int depth);
/**
* Saves the specified entity in the graph database. If the entity is currently transient then the persistent version
* of the entity will be returned, containing its new graph ID.
*
* @param entity The entity to save
* @return The saved entity
*/
<T> T save(T entity);
/**
* Saves the specified entity in the graph database to a custom depth. If the entity is currently transient then the
* persistent version of the entity will be returned, containing its new graph ID.
*
* @param entity The entity to save
* @param depth The maximum number of relationships away from the entity to follow when saving related entities. A
* value of 0 just saves the object's properties and no related entities. A value of -1 implies no depth
* limit.
* @return The saved entity
*/
<T> T save(T entity, int depth);
/**
* Removes the given node or relationship entity from the graph. The entity is first removed from all indexes and then
* deleted.
*
* @param entity The entity to delete
*/
void delete(Object entity);
/**
* Removes all nodes or relationship entities of a specific type from the graph.
*
* @param type the type of entity to delete
*/
<T> void deleteAll(Class<T> type);
/**
* Removes all mapping information from the current session
*/
void clear();
/**
* Executes the specified Cypher query with the given parameters against the underlying Neo4j database and returns the
* row-based result in the form of an {@link Iterable} of {@link Map}s.
* <p>
* Each of the resultant maps corresponds to a "row" in the result set and the key set in each map contains all the
* names contained in the <code>RETURN</code> clause of the given query.
* </p>
*
* @param cypherQuery The Cypher query to execute
* @param params The parameter to merge into the cypher query or an empty {@link Map} if the given query isn't
* parameterised
* @return A {@link Query} containing an {@link Iterable} map representing query results and {@link QueryStatistics}
* if applicable.
* @throws RuntimeException if the given query is not a valid Cypherquery
*/
Result query(String cypherQuery, Map<String, ?> params);
/**
* Runs the specified Cypher query with the given parameters against the underlying Neo4j database and returns the
* result marshalled as an object of the requested type.
*
* @param entityType The {@link Class} denoting the type of entity to return
* @param cypherQuery The Cypher query to execute
* @param parameters The parameter to merge into the Cypher query or an empty {@link Map} if the query's not
* parameterised
* @return An instance of T that corresponds to the entity found by executing the query or <code>null</code> if
* nothing is found by the query
* @throws RuntimeException If more than one result is returned or there's an issue executing the query
*/
<T> T queryForObject(Class<T> entityType, String cypherQuery, Map<String, ?> parameters);
/**
* Runs the specified Cypher query with the given parameters against the underlying Neo4j database and returns the
* result marshalled as a group of objects of the requested type.
*
* @param entityType The {@link Class} denoting the type of entity to return
* @param cypherQuery The Cypher query to execute
* @param parameters The parameter to merge into the Cypher query or an empty {@link Map} if the query's not
* parameterised
* @return An {@link Iterable} over the entities found by executing the query or an empty <code>Iterable</code> if
* nothing is found by the query, never <code>null</code>
* @throws RuntimeException If there's an issue executing the query
*/
<T> Iterable<T> queryForObjects(Class<T> entityType, String cypherQuery, Map<String, ?> parameters);
/**
* Given a cypher statement this method will return a {@link Query} object containing a collection of Map's which
* represent Neo4j objects as properties, along with query statistics if applicable. Each element of the query result
* is a map which you can access by the name of the returned field TODO: Are we going to use the neo4jOperations
* conversion method to cast the value object to its proper class?
*
* @param cypher The parametrisable cypher to execute.
* @param parameters Any parameters to attach to the cypher.
* @param readOnly true if the query is readOnly, false otherwise
* @return A {@link Query} of {@link Iterable}s with each entry representing a neo4j object's properties.
*/
Result query(String cypher, Map<String, ?> parameters, boolean readOnly);
/**
* Provides the instance count for the given <em>node</em> entity type. This method is also provided by the
* corresponding repository.
*
* @param entityClass The {@link Class} representing the type of node entity to count
* @return The number of entities in the database of the given type
*/
long count(Class<?> entityClass);
// /**
// * Issue a single Cypher update operation (such as a <tt>CREATE</tt>, <tt>MERGE</tt> or <tt>DELETE</tt> statement).
// *
// * @deprecated Use {@link Neo4jOperations}.query() to return both results as well as query statistics.
// * @param cypherQuery The Cypher query to execute
// * @return {@link QueryStatistics} representing statistics about graph modifications as a result of the cypher
// execution.
// */
// @Deprecated
// QueryStatistics execute(String cypherQuery);
// /**
// * Allows a cypher statement with a modification statement to be executed.
// *
// * <p>Parameters may be scalars or domain objects themselves.</p>
// * @deprecated Use {@link Neo4jOperations}.query() to return both results as well as query statistics.
// * @param cypher The parametrisable cypher to execute.
// * @param parameters Any parameters to attach to the cypher. These may be domain objects or scalars. Note that
// * if a complex domain object is provided only the properties of that object will be set.
// * If relationships of a provided object also need to be set then the cypher should reflect this
// * and further domain object parameters provided.
// *
// * @return {@link QueryStatistics} representing statistics about graph modifications as a result of the cypher
// execution.
// */
// @Deprecated
// QueryStatistics execute(String cypher, Map<String, Object> parameters);
}

View File

@@ -13,7 +13,6 @@
package org.springframework.data.neo4j.template;
import static org.springframework.data.neo4j.util.IterableUtils.*;
import java.util.Collection;
@@ -35,12 +34,12 @@ import org.springframework.data.neo4j.transaction.SessionFactoryUtils;
import org.springframework.util.Assert;
/**
* Spring Data template for Neo4j, which is an implementation of {@link Neo4jOperations}. Indeed, framework users are encouraged
* to favour coding against the {@link Neo4jOperations} interface rather than the {@link Neo4jTemplate} directly, as the
* interface API will be more consistent over time and enhanced proxy objects of the interface may actually be created by Spring
* for auto-wiring instead of this template.
* Please note also that all methods on this class throw a {@link DataAccessException} if any underlying {@code Exception} is
* thrown. Since {@link DataAccessException} is a runtime exception, this is not documented at the method level.
* Spring Data template for Neo4j, which is an implementation of {@link Neo4jOperations}. Indeed, framework users are
* encouraged to favour coding against the {@link Neo4jOperations} interface rather than the {@link Neo4jTemplate}
* directly, as the interface API will be more consistent over time and enhanced proxy objects of the interface may
* actually be created by Spring for auto-wiring instead of this template. Please note also that all methods on this
* class throw a {@link DataAccessException} if any underlying {@code Exception} is thrown. Since
* {@link DataAccessException} is a runtime exception, this is not documented at the method level.
*
* @author Adam George
* @author Michal Bachman
@@ -58,8 +57,7 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
/**
* Create a new Neo4jTemplate instance.
*/
public Neo4jTemplate() {
}
public Neo4jTemplate() {}
/**
* Constructs a new {@link Neo4jTemplate} based on the given Neo4j OGM {@link SessionFactory}.
@@ -88,7 +86,6 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
}
}
@Override
public <T> T execute(Neo4jCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
@@ -185,7 +182,8 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
}
@Override
public <T> Collection<T> loadAll(final Class<T> type, final SortOrder sortOrder, final Pagination pagination, final int depth) {
public <T> Collection<T> loadAll(final Class<T> type, final SortOrder sortOrder, final Pagination pagination,
final int depth) {
return execute(new Neo4jCallback<Collection<T>>() {
@Override
public Collection<T> doInNeo4jOgm(Session session) {
@@ -214,7 +212,8 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
}
@Override
public <T> Collection<T> loadAll(final Class<T> type, final Collection<Long> ids, final SortOrder sortOrder, final int depth) {
public <T> Collection<T> loadAll(final Class<T> type, final Collection<Long> ids, final SortOrder sortOrder,
final int depth) {
return execute(new Neo4jCallback<Collection<T>>() {
@Override
public Collection<T> doInNeo4jOgm(Session session) {
@@ -264,7 +263,8 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
}
@Override
public <T> T loadByProperty(final Class<T> type, final String propertyName, final Object propertyValue, final int depth) {
public <T> T loadByProperty(final Class<T> type, final String propertyName, final Object propertyValue,
final int depth) {
return execute(new Neo4jCallback<T>() {
@Override
public T doInNeo4jOgm(Session session) {
@@ -312,7 +312,8 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
});
}
public <T> Collection<T> loadAllByProperty(final Class<T> type, final String name, final Object value, final int depth) {
public <T> Collection<T> loadAllByProperty(final Class<T> type, final String name, final Object value,
final int depth) {
return execute(new Neo4jCallback<Collection<T>>() {
@Override
public Collection<T> doInNeo4jOgm(Session session) {
@@ -353,7 +354,6 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
});
}
@Override
public <T> T save(final T entity) {
return execute(new Neo4jCallback<T>() {
@@ -386,7 +386,8 @@ public class Neo4jTemplate implements Neo4jOperations, InitializingBean {
}
@Override
public <T> Iterable<T> queryForObjects(final Class<T> objectType, final String cypher, final Map<String, ?> parameters) {
public <T> Iterable<T> queryForObjects(final Class<T> objectType, final String cypher,
final Map<String, ?> parameters) {
return execute(new Neo4jCallback<Iterable<T>>() {
@Override
public Iterable<T> doInNeo4jOgm(Session session) {

View File

@@ -13,7 +13,6 @@
package org.springframework.data.neo4j.transaction;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.transaction.Transaction;
@@ -34,30 +33,29 @@ import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* {@link PlatformTransactionManager} implementation
* for a single Neo4j OGM {@link SessionFactory}. Binds a Neo4j OGM
* Session from the specified factory to the thread, potentially allowing for
* one thread-bound Session per factory. {@link SharedSessionCreator}
* is aware of thread-bound session and participates
* in such transactions automatically. It is required for Neo4j OGM access code
* supporting this transaction management mechanism.
* <p>This transaction manager is appropriate for applications that use a single
* Neo4j OGM SessionFactory for transactional data access. JTA (usually through
* {@link org.springframework.transaction.jta.JtaTransactionManager}) has not been tested
* or considered at the moment.
* <p>This transaction manager does not support nested transactions or
* requires new propagation.
* {@link PlatformTransactionManager} implementation for a single Neo4j OGM {@link SessionFactory}. Binds a Neo4j OGM
* Session from the specified factory to the thread, potentially allowing for one thread-bound Session per factory.
* {@link SharedSessionCreator} is aware of thread-bound session and participates in such transactions automatically. It
* is required for Neo4j OGM access code supporting this transaction management mechanism.
* <p>
* This transaction manager is appropriate for applications that use a single Neo4j OGM SessionFactory for transactional
* data access. JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager}) has not been
* tested or considered at the moment.
* <p>
* This transaction manager does not support nested transactions or requires new propagation.
*
* @author Mark Angrish
* @see #setSessionFactory
*/
public class Neo4jTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
private SessionFactory sessionFactory;
/**
* Create a new Neo4jTransactionManager instance.
* <p>An SessionFactory has to be set to be able to use it.
* <p>
* An SessionFactory has to be set to be able to use it.
*
* @see #setSessionFactory(SessionFactory)
*/
@@ -65,7 +63,6 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
setTransactionSynchronization(SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
}
/**
* Create a new Neo4jTransactionManager instance.
*
@@ -76,17 +73,16 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
this.sessionFactory = sessionFactory;
}
/**
* Set the SessionFactory that this instance should manage transactions for.
* <p>By default, a default SessionFactory will be retrieved by finding a
* single unique bean of type SessionFactory in the containing BeanFactory.
* <p>
* By default, a default SessionFactory will be retrieved by finding a single unique bean of type SessionFactory in
* the containing BeanFactory.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Return the SessionFactory that this instance should manage transactions for.
*/
@@ -94,7 +90,6 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
return this.sessionFactory;
}
/**
* Retrieves a default SessionFactory bean.
*/
@@ -105,7 +100,6 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
}
@Override
public void afterPropertiesSet() throws Exception {
if (getSessionFactory() == null) {
@@ -113,13 +107,11 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
}
@Override
public Object getResourceFactory() {
return getSessionFactory();
}
@Override
protected Object doGetTransaction() {
Neo4jTransactionObject txObject = new Neo4jTransactionObject();
@@ -127,28 +119,24 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() +
"] for Neo4j OGM transaction");
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Neo4j OGM transaction");
}
txObject.setSessionHolder(sessionHolder, false);
}
return txObject;
}
@Override
protected boolean isExistingTransaction(Object transaction) {
return ((Neo4jTransactionObject) transaction).hasTransaction();
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
Neo4jTransactionObject txObject = (Neo4jTransactionObject) transaction;
try {
if (txObject.getSessionHolder() == null ||
txObject.getSessionHolder().isSynchronizedWithTransaction()) {
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Session session = sessionFactory.openSession();
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + session + "] for Neo4j OGM transaction");
@@ -165,12 +153,11 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
if (definition.getPropagationBehavior() != TransactionDefinition.PROPAGATION_REQUIRED) {
throw new IllegalTransactionStateException(
"Neo4jTransactionManager only supports 'required' propagation.");
throw new IllegalTransactionStateException("Neo4jTransactionManager only supports 'required' propagation.");
}
Transaction transactionData;
if (definition.isReadOnly() && txObject.isNewSessionHolder()) {
if (definition.isReadOnly() && txObject.isNewSessionHolder()) {
transactionData = session.beginTransaction(Transaction.Type.READ_ONLY);
} else {
transactionData = session.beginTransaction();
@@ -200,10 +187,8 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
}
/**
* Close the current transaction's Session.
* Called after a transaction begin attempt failed.
* Close the current transaction's Session. Called after a transaction begin attempt failed.
*
* @param txObject the current transaction
*/
@@ -222,17 +207,14 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
}
@Override
protected Object doSuspend(Object transaction) {
Neo4jTransactionObject txObject = (Neo4jTransactionObject) transaction;
txObject.setSessionHolder(null, false);
SessionHolder sessionHolder = (SessionHolder)
TransactionSynchronizationManager.unbindResource(getSessionFactory());
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
return new SuspendedResourcesHolder(sessionHolder);
}
@Override
protected void doResume(Object transaction, Object suspendedResources) {
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
@@ -241,11 +223,9 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
// -> can be safely removed, will be closed on transaction completion.
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
TransactionSynchronizationManager.bindResource(
getSessionFactory(), resourcesHolder.getSessionHolder());
TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
@@ -267,7 +247,6 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
Neo4jTransactionObject txObject = (Neo4jTransactionObject) status.getTransaction();
@@ -293,18 +272,16 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
}
@Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
Neo4jTransactionObject txObject = (Neo4jTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting Neo4j OGM transaction on Session [" +
txObject.getSessionHolder().getSession() + "] rollback-only");
logger.debug(
"Setting Neo4j OGM transaction on Session [" + txObject.getSessionHolder().getSession() + "] rollback-only");
}
status.setRollbackOnly();
}
@Override
protected void doCleanupAfterCompletion(Object transaction) {
Neo4jTransactionObject txObject = (Neo4jTransactionObject) transaction;
@@ -336,8 +313,7 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
/**
* Neo4j OGM transaction object, representing a SessionHolder.
* Used as transaction object by Neo4jTransactionManager.
* Neo4j OGM transaction object, representing a SessionHolder. Used as transaction object by Neo4jTransactionManager.
*/
private static class Neo4jTransactionObject {
@@ -347,8 +323,7 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
private Transaction transactionData;
void setSessionHolder(
SessionHolder sessionHolder, boolean newSessionHolder) {
void setSessionHolder(SessionHolder sessionHolder, boolean newSessionHolder) {
this.sessionHolder = sessionHolder;
this.newSessionHolder = newSessionHolder;
}
@@ -376,8 +351,7 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager
}
/**
* Holder for suspended resources.
* Used internally by {@code doSuspend} and {@code doResume}.
* Holder for suspended resources. Used internally by {@code doSuspend} and {@code doResume}.
*/
private static class SuspendedResourcesHolder {

View File

@@ -37,10 +37,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import org.springframework.util.Assert;
/**
* Helper class featuring methods for Neo4j OGM Session handling,
* allowing for reuse of Session instances within transactions.
* Also provides support for exception translation.
* <p>Mainly intended for internal use within the framework.
* Helper class featuring methods for Neo4j OGM Session handling, allowing for reuse of Session instances within
* transactions. Also provides support for exception translation.
* <p>
* Mainly intended for internal use within the framework.
*
* @author Mark Angrish
*/
@@ -48,9 +48,7 @@ public class SessionFactoryUtils {
private static final Logger logger = LoggerFactory.getLogger(SessionFactoryUtils.class);
public static void closeSession(Session session) {
}
public static void closeSession(Session session) {}
public static Session getSession(SessionFactory sessionFactory) throws IllegalStateException {
@@ -58,11 +56,11 @@ public class SessionFactoryUtils {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null) {
if (!sessionHolder.isSynchronizedWithTransaction() &&
TransactionSynchronizationManager.isSynchronizationActive()) {
if (!sessionHolder.isSynchronizedWithTransaction()
&& TransactionSynchronizationManager.isSynchronizationActive()) {
sessionHolder.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.registerSynchronization(
new SessionSynchronization(sessionHolder, sessionFactory, false));
TransactionSynchronizationManager
.registerSynchronization(new SessionSynchronization(sessionHolder, sessionFactory, false));
}
return sessionHolder.getSession();
}
@@ -83,22 +81,20 @@ public class SessionFactoryUtils {
sessionHolder = new SessionHolder(session);
sessionHolder.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.registerSynchronization(
new SessionSynchronization(sessionHolder, sessionFactory, true));
TransactionSynchronizationManager
.registerSynchronization(new SessionSynchronization(sessionHolder, sessionFactory, true));
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
return session;
}
/**
* Convert the given runtime exception to an appropriate exception from the
* {@code org.springframework.dao} hierarchy.
* Return null if no translation is appropriate: any other exception may
* have resulted from user code, and should not be translated.
* Convert the given runtime exception to an appropriate exception from the {@code org.springframework.dao} hierarchy.
* Return null if no translation is appropriate: any other exception may have resulted from user code, and should not
* be translated.
*
* @param ex runtime exception that occurred
* @return the corresponding DataAccessException instance,
* or {@code null} if the exception should not be translated
* @return the corresponding DataAccessException instance, or {@code null} if the exception should not be translated
*/
public static DataAccessException convertOgmAccessException(RuntimeException ex) {
@@ -161,9 +157,11 @@ public class SessionFactoryUtils {
if (dae != null) {
try {
final Constructor<? extends DataAccessException> constructor = dae.getDeclaredConstructor(String.class, Throwable.class);
final Constructor<? extends DataAccessException> constructor = dae.getDeclaredConstructor(String.class,
Throwable.class);
return constructor.newInstance(ex.getMessage(), ex);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException
| InvocationTargetException e) {
return null;
}
}
@@ -176,15 +174,12 @@ public class SessionFactoryUtils {
return null;
}
private static class SessionSynchronization
extends ResourceHolderSynchronization<SessionHolder, SessionFactory>
private static class SessionSynchronization extends ResourceHolderSynchronization<SessionHolder, SessionFactory>
implements Ordered {
private final boolean newSession;
SessionSynchronization(
SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) {
SessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory, boolean newSession) {
super(sessionHolder, sessionFactory);
this.newSession = newSession;
}
@@ -195,8 +190,7 @@ public class SessionFactoryUtils {
}
@Override
public void flushResource(SessionHolder resourceHolder) {
}
public void flushResource(SessionHolder resourceHolder) {}
@Override
protected boolean shouldUnbindAtCompletion() {
@@ -205,7 +199,7 @@ public class SessionFactoryUtils {
@Override
protected boolean shouldReleaseAfterCompletion(SessionHolder resourceHolder) {
// return !resourceHolder.getSession().isClosed();
// return !resourceHolder.getSession().isClosed();
return false;
}
}

View File

@@ -18,11 +18,10 @@ import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* Holder wrapping a Neo4j OGM Session.
* Neo4jTransactionManager binds instances of this class to the thread,
* for a given SessionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
* Holder wrapping a Neo4j OGM Session. Neo4jTransactionManager binds instances of this class to the thread, for a given
* SessionFactory.
* <p>
* Note: This is an SPI class, not intended to be used by applications.
*
* @author Mark Angrish
* @see Neo4jTransactionManager
@@ -39,7 +38,6 @@ public class SessionHolder extends ResourceHolderSupport {
this.session = session;
}
public Session getSession() {
return this.session;
}
@@ -52,7 +50,6 @@ public class SessionHolder extends ResourceHolderSupport {
return this.transactionActive;
}
@Override
public void clear() {
super.clear();

View File

@@ -30,12 +30,11 @@ import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Delegate for creating a shareable Neo4j OGM {@link Session}
* reference for a given {@link SessionFactory}.
* <p>A shared Session will behave just like a Session fetched from
* an application SessionFactory.
* It will delegate all calls to the current transactional Session, if any;
* otherwise it will fall back to a newly created Session per operation.
* Delegate for creating a shareable Neo4j OGM {@link Session} reference for a given {@link SessionFactory}.
* <p>
* A shared Session will behave just like a Session fetched from an application SessionFactory. It will delegate all
* calls to the current transactional Session, if any; otherwise it will fall back to a newly created Session per
* operation.
*
* @author Mark Angrish
* @see Neo4jTransactionManager
@@ -54,22 +53,18 @@ public class SharedSessionCreator {
/**
* Create a transactional Session proxy for the given SessionFactory.
*
* @param sessionFactory SessionFactory to obtain Sessions from as needed
* {@code createSession} call (may be {@code null})
* Session. Allows the addition or specification of proprietary interfaces.
* @param sessionFactory SessionFactory to obtain Sessions from as needed {@code createSession} call (may be
* {@code null}) Session. Allows the addition or specification of proprietary interfaces.
* @return a shareable transactional Session proxy
*/
public static Session createSharedSession(SessionFactory sessionFactory) {
return (Session) Proxy.newProxyInstance(
SharedSessionCreator.class.getClassLoader(),
new Class<?>[]{Session.class}, new SharedSessionInvocationHandler(sessionFactory));
return (Session) Proxy.newProxyInstance(SharedSessionCreator.class.getClassLoader(),
new Class<?>[] { Session.class }, new SharedSessionInvocationHandler(sessionFactory));
}
/**
* Invocation handler that delegates all calls to the current
* transactional Session, if any; else, it will fall back
* Invocation handler that delegates all calls to the current transactional Session, if any; else, it will fall back
* to a newly created Session per operation.
*/
private static class SharedSessionInvocationHandler implements InvocationHandler {
@@ -84,7 +79,6 @@ public class SharedSessionCreator {
this.proxyClassLoader = this.targetFactory.getClass().getClassLoader();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Invocation on Session interface coming in...
@@ -100,8 +94,7 @@ public class SharedSessionCreator {
return "Shared Session proxy for target factory [" + targetFactory + "]";
} else if (method.getName().equals("beginTransaction")) {
throw new IllegalStateException(
"Not allowed to create transaction on shared Session - " +
"use Spring transactions instead");
"Not allowed to create transaction on shared Session - " + "use Spring transactions instead");
}
// Determine current Session: either the transactional one
@@ -109,11 +102,11 @@ public class SharedSessionCreator {
Session target = SessionFactoryUtils.getSession(this.targetFactory);
if (transactionRequiringMethods.contains(method.getName())) {
if (target == null || (!TransactionSynchronizationManager.isActualTransactionActive()
&& target.getTransaction() != null
&& EnumSet.of(CLOSED, COMMITTED, ROLLEDBACK).contains(target.getTransaction().status()))) {
throw new IllegalStateException("No Session with actual transaction available " +
"for current thread - cannot reliably process '" + method.getName() + "' call");
if (target == null
|| (!TransactionSynchronizationManager.isActualTransactionActive() && target.getTransaction() != null
&& EnumSet.of(CLOSED, COMMITTED, ROLLEDBACK).contains(target.getTransaction().status()))) {
throw new IllegalStateException("No Session with actual transaction available "
+ "for current thread - cannot reliably process '" + method.getName() + "' call");
}
}

View File

@@ -13,13 +13,13 @@
package org.springframework.data.neo4j.util;
import org.neo4j.ogm.exception.NotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.neo4j.ogm.exception.NotFoundException;
/**
* Utility methods for dealing with {@link Iterable}s.
*
@@ -27,229 +27,228 @@ import java.util.List;
*/
public final class IterableUtils {
/**
* Count items in an iterable.
*
* @param iterable to count items in.
* @return number of items in the iterable.
*/
public static long count(Iterable iterable) {
if (iterable instanceof Collection) {
return ((Collection) iterable).size();
}
/**
* Count items in an iterable.
*
* @param iterable to count items in.
* @return number of items in the iterable.
*/
public static long count(Iterable iterable) {
if (iterable instanceof Collection) {
return ((Collection) iterable).size();
}
int count = 0;
for (Object o : iterable) {
count++;
}
int count = 0;
for (Object o : iterable) {
count++;
}
return count;
}
return count;
}
/**
* Check whether an iterable contains the given object.
*
* @param iterable to check in.
* @param object to look for.
* @param <T> type of the objects stored in the iterable.
* @return true iff the object is contained in the iterable.
*/
public static <T> boolean contains(Iterable<T> iterable, T object) {
if (iterable instanceof Collection) {
return ((Collection) iterable).contains(object);
}
/**
* Check whether an iterable contains the given object.
*
* @param iterable to check in.
* @param object to look for.
* @param <T> type of the objects stored in the iterable.
* @return true iff the object is contained in the iterable.
*/
public static <T> boolean contains(Iterable<T> iterable, T object) {
if (iterable instanceof Collection) {
return ((Collection) iterable).contains(object);
}
for (T t : iterable) {
if (t.equals(object)) {
return true;
}
}
for (T t : iterable) {
if (t.equals(object)) {
return true;
}
}
return false;
}
return false;
}
/**
* Convert an iterable to a list.
*
* @param iterable to convert.
* @param <T> type of the items held.
* @return a list.
*/
public static <T> List<T> toList(Iterable<T> iterable) {
List<T> list = new ArrayList<>();
/**
* Convert an iterable to a list.
*
* @param iterable to convert.
* @param <T> type of the items held.
* @return a list.
*/
public static <T> List<T> toList(Iterable<T> iterable) {
List<T> list = new ArrayList<>();
if (iterable instanceof Collection) {
list.addAll((Collection<T>) iterable);
} else {
for (T next : iterable) {
list.add(next);
}
}
if (iterable instanceof Collection) {
list.addAll((Collection<T>) iterable);
} else {
for (T next : iterable) {
list.add(next);
}
}
return list;
}
return list;
}
/**
* Get a single element from iterator.
*
* @param iterator to find a single element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterator<T> iterator, String notFoundMessage) {
T result = getSingleOrNull(iterator);
/**
* Get a single element from iterator.
*
* @param iterator to find a single element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterator<T> iterator, String notFoundMessage) {
T result = getSingleOrNull(iterator);
if (result == null) {
throw new NotFoundException(notFoundMessage);
}
if (result == null) {
throw new NotFoundException(notFoundMessage);
}
return result;
}
return result;
}
/**
* Get a single element from iterable.
*
* @param iterable to find a single element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterable<T> iterable, String notFoundMessage) {
return getSingle(iterable.iterator(), notFoundMessage);
}
/**
* Get a single element from iterable.
*
* @param iterable to find a single element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterable<T> iterable, String notFoundMessage) {
return getSingle(iterable.iterator(), notFoundMessage);
}
/**
* Get a single element from iterator.
*
* @param iterator to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterator<T> iterator) {
return getSingle(iterator, "Iterator is empty");
}
/**
* Get a single element from iterator.
*
* @param iterator to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterator<T> iterator) {
return getSingle(iterator, "Iterator is empty");
}
/**
* Get a single element from iterable.
*
* @param iterable to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterable<T> iterable) {
return getSingle(iterable.iterator(), "Iterable is empty");
}
/**
* Get a single element from iterable.
*
* @param iterable to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one.
* @throws NotFoundException in case there are no elements.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingle(Iterable<T> iterable) {
return getSingle(iterable.iterator(), "Iterable is empty");
}
/**
* Get a single element from iterator.
*
* @param iterator to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one, null iff there is 0.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingleOrNull(Iterator<T> iterator) {
T result = null;
/**
* Get a single element from iterator.
*
* @param iterator to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one, null iff there is 0.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingleOrNull(Iterator<T> iterator) {
T result = null;
if (iterator.hasNext()) {
result = iterator.next();
}
if (iterator.hasNext()) {
result = iterator.next();
}
if (iterator.hasNext()) {
throw new IllegalStateException("Iterable has more than one element, which is unexpected");
}
if (iterator.hasNext()) {
throw new IllegalStateException("Iterable has more than one element, which is unexpected");
}
return result;
}
return result;
}
/**
* Get a single element from iterable.
*
* @param iterable to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one, null iff there is 0.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingleOrNull(Iterable<T> iterable) {
return getSingleOrNull(iterable.iterator());
}
/**
* Get a single element from iterable.
*
* @param iterable to find a single element.
* @param <T> type of the element.
* @return the element iff there is exactly one, null iff there is 0.
* @throws IllegalStateException in case the iterable contains more than 1 element.
*/
public static <T> T getSingleOrNull(Iterable<T> iterable) {
return getSingleOrNull(iterable.iterator());
}
/**
* Get the first element from iterator.
*
* @param iterator to find the first element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is one or more.
* @throws NotFoundException in case there are no elements.
*/
public static <T> T getFirst(Iterator<T> iterator, String notFoundMessage) {
T result = null;
/**
* Get the first element from iterator.
*
* @param iterator to find the first element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is one or more.
* @throws NotFoundException in case there are no elements.
*/
public static <T> T getFirst(Iterator<T> iterator, String notFoundMessage) {
T result = null;
if (iterator.hasNext()) {
result = iterator.next();
}
if (iterator.hasNext()) {
result = iterator.next();
}
if (result == null) {
throw new NotFoundException(notFoundMessage);
}
if (result == null) {
throw new NotFoundException(notFoundMessage);
}
return result;
}
return result;
}
/**
* Get the first element from iterable.
*
* @param iterable to find the first element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is one or more.
* @throws NotFoundException in case there are no elements.
*/
public static <T> T getFirst(Iterable<T> iterable, String notFoundMessage) {
return getFirst(iterable.iterator(), notFoundMessage);
}
/**
* Get the first element from iterable.
*
* @param iterable to find the first element.
* @param notFoundMessage exception message if there are no elements.
* @param <T> type of the element.
* @return the element iff there is one or more.
* @throws NotFoundException in case there are no elements.
*/
public static <T> T getFirst(Iterable<T> iterable, String notFoundMessage) {
return getFirst(iterable.iterator(), notFoundMessage);
}
/**
* Get the first element from iterator.
*
* @param iterator to find the first element.
* @param <T> type of the element.
* @return the element iff there is one or more, null if there is none.
*/
public static <T> T getFirstOrNull(Iterator<T> iterator) {
T result = null;
/**
* Get the first element from iterator.
*
* @param iterator to find the first element.
* @param <T> type of the element.
* @return the element iff there is one or more, null if there is none.
*/
public static <T> T getFirstOrNull(Iterator<T> iterator) {
T result = null;
if (iterator.hasNext()) {
result = iterator.next();
}
if (iterator.hasNext()) {
result = iterator.next();
}
return result;
}
return result;
}
/**
* Get the first element from iterable.
*
* @param iterable to find the first element.
* @param <T> type of the element.
* @return the element iff there is one or more, null if there is none.
*/
public static <T> T getFirstOrNull(Iterable<T> iterable) {
return getFirstOrNull(iterable.iterator());
}
/**
* Get the first element from iterable.
*
* @param iterable to find the first element.
* @param <T> type of the element.
* @return the element iff there is one or more, null if there is none.
*/
public static <T> T getFirstOrNull(Iterable<T> iterable) {
return getFirstOrNull(iterable.iterator());
}
/**
* private constructor to prevent instantiation.
*/
private IterableUtils() {
}
/**
* private constructor to prevent instantiation.
*/
private IterableUtils() {}
}

View File

@@ -26,15 +26,14 @@ import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
/**
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and
* OpenSessionInViewInterceptor.
* Ensures the following:
* 1) The session is bound/unbound when "callable processing" is started
* 2) The session is closed if an async request times out
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and OpenSessionInViewInterceptor.
* Ensures the following: 1) The session is bound/unbound when "callable processing" is started 2) The session is closed
* if an async request times out
*
* @author Mark Angrish
*/
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter implements DeferredResultProcessingInterceptor {
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter
implements DeferredResultProcessingInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AsyncRequestInterceptor.class);
@@ -49,7 +48,6 @@ class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter imple
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
bindSession();
@@ -68,7 +66,7 @@ class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter imple
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {
this.timeoutInProgress = true;
return RESULT_NONE; // give other interceptors a chance to handle the timeout
return RESULT_NONE; // give other interceptors a chance to handle the timeout
}
@Override
@@ -80,13 +78,12 @@ class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter imple
if (this.timeoutInProgress) {
logger.debug("Closing Neo4j OGM Session after async request timeout");
// close session.
// SessionFactoryUtils.closeSession(session);
// SessionFactoryUtils.closeSession(session);
}
}
@Override
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) {
}
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) {}
@Override
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) {
@@ -101,11 +98,12 @@ class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter imple
@Override
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) {
this.timeoutInProgress = true;
return true; // give other interceptors a chance to handle the timeout
return true; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest nativeWebRequest, DeferredResult<T> deferredResult) throws Exception {
public <T> void afterCompletion(NativeWebRequest nativeWebRequest, DeferredResult<T> deferredResult)
throws Exception {
// Do nothing.
}
}

View File

@@ -13,16 +13,16 @@
package org.springframework.data.neo4j.web.support;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.transaction.SessionFactoryUtils;
import org.springframework.data.neo4j.transaction.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
@@ -33,16 +33,15 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Servlet Filter that binds a Neo4j OGM Session to the thread for the
* entire processing of the request. Intended for the "Open Session in
* View" pattern, i.e. to allow for lazy loading in web views despite the
* original transactions already being completed.
* <p>This filter makes OGM Sessions available via the current thread,
* which will be autodetected by transaction managers. At the moment this service is
* only suitable for transactions via {@link Neo4jTransactionManager}.
* <p>Looks up the SessionFactory in Spring's root web application context.
* Supports an "sessionFactoryBeanName" filter init-param in {@code web.xml};
* the default bean name is "sessionFactory".
* Servlet Filter that binds a Neo4j OGM Session to the thread for the entire processing of the request. Intended for
* the "Open Session in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions
* already being completed.
* <p>
* This filter makes OGM Sessions available via the current thread, which will be autodetected by transaction managers.
* At the moment this service is only suitable for transactions via {@link Neo4jTransactionManager}.
* <p>
* Looks up the SessionFactory in Spring's root web application context. Supports an "sessionFactoryBeanName" filter
* init-param in {@code web.xml}; the default bean name is "sessionFactory".
*
* @author Mark Angrish
* @see OpenSessionInViewInterceptor
@@ -63,9 +62,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
private volatile SessionFactory sessionFactory;
/**
* Set the bean name of the SessionFactory to fetch from Spring's
* root application context.
* <p>Default is "sessionFactory".
* Set the bean name of the SessionFactory to fetch from Spring's root application context.
* <p>
* Default is "sessionFactory".
*
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
*/
@@ -74,38 +73,31 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
/**
* Return the bean name of the SessionFactory to fetch from Spring's
* root application context.
* Return the bean name of the SessionFactory to fetch from Spring's root application context.
*/
protected String getSessionFactoryBeanName() {
return this.sessionFactoryBeanName;
}
/**
* Returns "false" so that the filter may re-bind the opened {@code Session}
* to each asynchronously dispatched thread and postpone closing it until the very
* last asynchronous dispatch.
* Returns "false" so that the filter may re-bind the opened {@code Session} to each asynchronously dispatched thread
* and postpone closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
/**
* Returns "false" so that the filter may provide an {@code Session}
* to each error dispatches.
* Returns "false" so that the filter may provide an {@code Session} to each error dispatches.
*/
@Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
SessionFactory sessionFactory = lookupSessionFactory(request);
@@ -139,17 +131,17 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
if (!isAsyncStarted(request)) {
logger.debug("Closed Neo4J OGM Session in OpenSessionInViewFilter");
// close session.
// SessionFactoryUtils.closeSession(session);
// SessionFactoryUtils.closeSession(session);
}
}
}
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
* <p>The default implementation delegates to the {@code lookupSessionFactory}
* without arguments, caching the SessionFactory reference once obtained.
* Look up the SessionFactory that this filter should use, taking the current HTTP request as argument.
* <p>
* The default implementation delegates to the {@code lookupSessionFactory} without arguments, caching the
* SessionFactory reference once obtained.
*
* @return the SessionFactory to use
* @see #lookupSessionFactory()
@@ -163,8 +155,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
/**
* Look up the SessionFactory that this filter should use.
* <p>The default implementation looks for a bean with the specified name
* in Spring's root application context.
* <p>
* The default implementation looks for a bean with the specified name in Spring's root application context.
*
* @return the SessionFactory to use
* @see #getSessionFactoryBeanName
@@ -182,10 +174,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
/**
* Create a Neo4j OGM Session to be bound to a request.
* <p>Can be overridden in subclasses.
* <p>
* Can be overridden in subclasses.
*
* @param sessionFactory the SessionFactory to use
* @see SessionFactory#openSession

View File

@@ -13,7 +13,6 @@
package org.springframework.data.neo4j.web.support;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.slf4j.Logger;
@@ -32,15 +31,15 @@ import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
/**
* Spring web request interceptor that binds a Neo4j OGM Session to the
* thread for the entire processing of the request. Intended for the "Open
* Session in View" pattern, i.e. to allow for lazy loading in
* web views despite the original transactions already being completed.
* <p>This interceptor makes Neo4j OGM Sessions available via the current thread,
* which will be autodetected by transaction managers. It is suitable for service
* layer transactions via {@link Neo4jTransactionManager}.
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is set
* up in a Spring application context and can thus take advantage of bean wiring.
* Spring web request interceptor that binds a Neo4j OGM Session to the thread for the entire processing of the request.
* Intended for the "Open Session in View" pattern, i.e. to allow for lazy loading in web views despite the original
* transactions already being completed.
* <p>
* This interceptor makes Neo4j OGM Sessions available via the current thread, which will be autodetected by transaction
* managers. It is suitable for service layer transactions via {@link Neo4jTransactionManager}.
* <p>
* In contrast to {@link OpenSessionInViewFilter}, this interceptor is set up in a Spring application context and can
* thus take advantage of bean wiring.
*
* @author Mark Angrish
* @see OpenSessionInViewFilter
@@ -55,8 +54,7 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
protected final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Suffix that gets appended to the SessionFactory toString
* representation for the "participate in existing session
* Suffix that gets appended to the SessionFactory toString representation for the "participate in existing session
* handling" request attribute.
*
* @see #getParticipateAttributeName
@@ -66,8 +64,7 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
private SessionFactory sessionFactory;
/**
* Set the Neo4j OGM SessionFactory that should be used to create
* Sessions.
* Set the Neo4j OGM SessionFactory that should be used to create Sessions.
*
* @see SessionFactory#openSession
*/
@@ -76,8 +73,7 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
}
/**
* Return the Neo4j OGM SessionFactory that should be used to create
* Sessions.
* Return the Neo4j OGM SessionFactory that should be used to create Sessions.
*/
public SessionFactory getSessionFactory() {
return this.sessionFactory;
@@ -93,7 +89,6 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
}
}
@Override
public void preHandle(WebRequest request) throws DataAccessException {
String participateAttributeName = getParticipateAttributeName();
@@ -123,8 +118,7 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
}
@Override
public void postHandle(WebRequest request, ModelMap model) {
}
public void postHandle(WebRequest request, ModelMap model) {}
@Override
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
@@ -132,7 +126,7 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
TransactionSynchronizationManager.unbindResource(getSessionFactory());
logger.debug("Closed Neo4j OGM Session in OpenSessionInViewInterceptor");
// close session.
// SessionFactoryUtils.closeSession(session);
// SessionFactoryUtils.closeSession(session);
}
}
@@ -159,9 +153,8 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
}
/**
* Return the name of the request attribute that identifies that a request is
* already filtered. Default implementation takes the toString representation
* of the SessionFactory instance and appends ".FILTERED".
* Return the name of the request attribute that identifies that a request is already filtered. Default implementation
* takes the toString representation of the SessionFactory instance and appends ".FILTERED".
*
* @see #PARTICIPATE_SUFFIX
*/
@@ -169,7 +162,6 @@ public class OpenSessionInViewInterceptor implements BeanFactoryAware, AsyncWebR
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
private boolean applyCallableInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;

View File

@@ -12,7 +12,6 @@
*/
package org.springframework.data.neo4j.domain.sample;
import java.util.UUID;
import org.neo4j.ogm.annotation.GraphId;
@@ -28,8 +27,7 @@ public class Role {
private static final String PREFIX = "ROLE_";
@GraphId
private Long id;
@GraphId private Long id;
private UUID uuid;
private String name;

View File

@@ -23,8 +23,7 @@ import org.springframework.util.Assert;
@NodeEntity
public class SampleEntity {
@GraphId
protected Long id;
@GraphId protected Long id;
private String first;
private String second;

View File

@@ -10,7 +10,6 @@ import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.typeconversion.DateString;
/**
* Domain class representing a person emphasizing the use of {@code AbstractEntity}. No declaration of an id is
* required. The id is typed by the parameterizable superclass.
@@ -18,8 +17,7 @@ import org.neo4j.ogm.annotation.typeconversion.DateString;
@NodeEntity
public class User {
@GraphId
private Long id;
@GraphId private Long id;
private String firstname;
@@ -33,11 +31,9 @@ public class User {
private String emailAddress;
@Relationship
private Set<User> colleagues;
@Relationship private Set<User> colleagues;
@Relationship
private Set<Role> roles;
@Relationship private Set<Role> roles;
private User manager;
@@ -47,8 +43,7 @@ public class User {
private Set<String> attributes;
@DateString
private Date dateOfBirth;
@DateString private Date dateOfBirth;
/**
* Creates a new empty instance of {@code User}.

View File

@@ -12,8 +12,7 @@ import org.springframework.stereotype.Component;
@Component
public class EventPublisher extends EventListenerAdapter {
@Autowired
private ApplicationEventPublisher publisher;
@Autowired private ApplicationEventPublisher publisher;
@Override
public void onPreSave(Event event) {

View File

@@ -1,7 +1,6 @@
package org.springframework.data.neo4j.events;
import org.springframework.context.event.EventListener;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Component;
/**
@@ -21,7 +20,7 @@ public class Neo4jModificationEventListener {
@EventListener
public void onPreSaveEvent(PreSaveEvent event) {
preSaveEvent= event;
preSaveEvent = event;
preSaveEventCount++;
}

View File

@@ -7,7 +7,7 @@ import org.neo4j.ogm.session.event.Event;
*/
public class PostDeleteEvent extends ModificationEvent {
public PostDeleteEvent( Event event) {
public PostDeleteEvent(Event event) {
super(event);
}
}

View File

@@ -7,7 +7,7 @@ import org.neo4j.ogm.session.event.Event;
*/
public class PreDeleteEvent extends ModificationEvent {
public PreDeleteEvent( Event event) {
public PreDeleteEvent(Event event) {
super(event);
}
}

View File

@@ -36,7 +36,7 @@ import org.springframework.transaction.annotation.Transactional;
* @author Luanne Misquitta
* @author Mark Angrish
*/
@ContextConfiguration(classes = {FriendContext.class})
@ContextConfiguration(classes = { FriendContext.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class FriendIT extends MultiDriverTestClass {
@@ -47,11 +47,10 @@ public class FriendIT extends MultiDriverTestClass {
@Autowired FriendService friendService;
@BeforeClass
public static void beforeClass(){
public static void beforeClass() {
graphDatabaseService = getGraphDatabaseService();
}
@Before
public void cleanUpDatabase() {
graphDatabaseService.execute("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE r, n");

View File

@@ -27,8 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
@Service
public class FriendService {
@Autowired
Session session;
@Autowired Session session;
@Transactional
public void createPersonAndFriends() {

View File

@@ -13,13 +13,13 @@
package org.springframework.data.neo4j.examples.friends.domain;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import java.util.HashSet;
import java.util.Set;
/**
* @author Luanne Misquitta
*/
@@ -30,8 +30,7 @@ public class Person {
private String firstName;
private String lastName;
@Relationship(type = "IS_FRIEND")
private Set<Friendship> friendships = new HashSet<>();
@Relationship(type = "IS_FRIEND") private Set<Friendship> friendships = new HashSet<>();
public Person() {}

View File

@@ -40,17 +40,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Vince Bickers
*/
@ContextConfiguration(classes = {GalaxyContext.class})
@ContextConfiguration(classes = { GalaxyContext.class })
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
public class GalaxyServiceIT extends MultiDriverTestClass {
@Autowired
private GalaxyService galaxyService;
@Autowired private GalaxyService galaxyService;
@Before
public void setUp() {
@@ -98,7 +96,6 @@ public class GalaxyServiceIT extends MultiDriverTestClass {
}
}
@Test
public void shouldFindWorldsByName() {
galaxyService.makeSomeWorlds();
@@ -140,9 +137,7 @@ public class GalaxyServiceIT extends MultiDriverTestClass {
galaxyService.makeSomeWorlds();
for (World worldWithOneMoon : galaxyService.findAllByNumberOfMoons(1)) {
assertThat(
worldWithOneMoon.getName(),
is(anyOf(containsString("Earth"), containsString("Midgard"))));
assertThat(worldWithOneMoon.getName(), is(anyOf(containsString("Earth"), containsString("Midgard"))));
}
}
@@ -218,11 +213,11 @@ public class GalaxyServiceIT extends MultiDriverTestClass {
sum += world.getId();
}
// note: this doesn't work, because deleted node ids are not reclaimed
// long sum = (size * size - size) / 2; // 0-based node ids
// long sum = (size * size - size) / 2; // 0-based node ids
Pageable pageable = new PageRequest(0, 3);
for (; ; ) {
for (;;) {
Page<World> page = galaxyService.findAllWorlds(pageable);
for (World world : page) {
System.out.println(world.getName() + ":" + world.getId());
@@ -249,7 +244,7 @@ public class GalaxyServiceIT extends MultiDriverTestClass {
Pageable pageable = new PageRequest(0, 3, Sort.Direction.ASC, "name");
int i = 0;
for (; ; ) {
for (;;) {
Page<World> page = galaxyService.findAllWorlds(pageable);
for (World world : page) {
assertEquals(sortedNames[i], world.getName());
@@ -306,7 +301,7 @@ public class GalaxyServiceIT extends MultiDriverTestClass {
names.add(world.getName());
}
String[] sortedNames = names.toArray(new String[]{});
String[] sortedNames = names.toArray(new String[] {});
Arrays.sort(sortedNames);
return sortedNames;
}

View File

@@ -28,34 +28,31 @@ import org.springframework.data.neo4j.examples.galaxy.domain.World;
import org.springframework.data.neo4j.examples.galaxy.repo.WorldRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
@ContextConfiguration(classes = {GalaxyContext.class})
@ContextConfiguration(classes = { GalaxyContext.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class WorldRepositoryIT extends MultiDriverTestClass {
@Autowired
WorldRepository worldRepository;
@Autowired WorldRepository worldRepository;
@Autowired
TransactionTemplate transactionTemplate;
@Autowired TransactionTemplate transactionTemplate;
boolean failed = false;
/**
* see https://jira.spring.io/browse/DATAGRAPH-951
*
* @throws Exception
*/
@Test
public void multipleThreadsResultsGetMixedUp() throws Exception {
World world1 = new World("world 1", 1);
worldRepository.save(world1, 0);
World world1 = new World("world 1", 1);
worldRepository.save(world1, 0);
World world2 = new World("world 2", 2);
worldRepository.save(world2, 0);
World world2 = new World("world 2", 2);
worldRepository.save(world2, 0);
int iterations = 10;

View File

@@ -29,7 +29,7 @@ import org.springframework.transaction.support.TransactionTemplate;
* @author Mark Angrish
*/
@Configuration
@ComponentScan({"org.springframework.data.neo4j.examples.galaxy.service"})
@ComponentScan({ "org.springframework.data.neo4j.examples.galaxy.service" })
@PropertySource("classpath:helloworld.properties")
@EnableNeo4jRepositories("org.springframework.data.neo4j.examples.galaxy.repo")
@EnableTransactionManagement
@@ -46,7 +46,7 @@ public class GalaxyContext {
}
@Bean
public TransactionTemplate transactionTemplate() {
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(transactionManager());
}

View File

@@ -13,116 +13,118 @@
package org.springframework.data.neo4j.examples.galaxy.domain;
import org.neo4j.ogm.annotation.Relationship;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.ogm.annotation.Relationship;
/**
* @author Vince Bickers
* @author Luanne Misquitta
*/
public class World {
private final static String REACHABLE_BY_ROCKET = "REACHABLE_BY_ROCKET";
private final static String REACHABLE_BY_ROCKET = "REACHABLE_BY_ROCKET";
private Long id;
private Long id;
private String name;
private String name;
private int moons;
private int moons;
private Float radius;
private Float radius;
private Long updated;
private Long updated;
public Long getUpdated() {
return updated;
}
public Long getUpdated() {
return updated;
}
public void setUpdated(long updated) {
this.updated = updated;
}
public void setUpdated(long updated) {
this.updated = updated;
}
private Set<World> reachableByRocket = new HashSet<>();
private Set<World> reachableByRocket = new HashSet<>();
public World(String name, int moons) {
this.name = name;
this.moons = moons;
}
public World(String name, int moons) {
this.name = name;
this.moons = moons;
}
public World() {}
public World() {
}
public Long getId() {
return id;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public int getMoons() {
return moons;
}
public int getMoons() {
return moons;
}
public void addRocketRouteTo(World otherWorld) {
reachableByRocket.add(otherWorld);
// symmetric relationship.
otherWorld.reachableByRocket.add(this); // bi-directional in domain.
}
public void addRocketRouteTo(World otherWorld) {
reachableByRocket.add(otherWorld);
// symmetric relationship.
otherWorld.reachableByRocket.add(this); // bi-directional in domain.
}
@Relationship(type = REACHABLE_BY_ROCKET, direction = "UNDIRECTED")
public Set<World> getReachableByRocket() {
return this.reachableByRocket;
}
@Relationship(type=REACHABLE_BY_ROCKET, direction = "UNDIRECTED")
public Set<World> getReachableByRocket() {
return this.reachableByRocket;
}
@Relationship(type = REACHABLE_BY_ROCKET, direction = "UNDIRECTED")
public void setReachableByRocket(Set<World> reachableByRocket) {
this.reachableByRocket.clear();
this.reachableByRocket = reachableByRocket;
}
@Relationship(type=REACHABLE_BY_ROCKET , direction = "UNDIRECTED")
public void setReachableByRocket(Set<World> reachableByRocket) {
this.reachableByRocket.clear();
this.reachableByRocket = reachableByRocket;
}
public boolean canBeReachedFrom(World otherWorld) {
for (World world : reachableByRocket) {
if (world.equals(otherWorld)) {
return true;
}
}
return false;
}
public boolean canBeReachedFrom(World otherWorld) {
for(World world : reachableByRocket) {
if(world.equals(otherWorld)) {
return true;
}
}
return false;
}
public Float getRadius() {
return radius;
}
public Float getRadius() {
return radius;
}
public void setRadius(Float radius) {
this.radius = radius;
}
public void setRadius(Float radius) {
this.radius = radius;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
World world = (World) o;
World world = (World) o;
if (moons != world.moons)
return false;
if (id != null ? !id.equals(world.id) : world.id != null)
return false;
return !(name != null ? !name.equals(world.name) : world.name != null);
}
if (moons != world.moons) return false;
if (id != null ? !id.equals(world.id) : world.id != null) return false;
return !(name != null ? !name.equals(world.name) : world.name != null);
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + moons;
return result;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + moons;
return result;
}
@Override
public String toString() {
return String.format("World{name='%s', moons=%d}", name, moons);
}
@Override
public String toString() {
return String.format("World{name='%s', moons=%d}", name, moons);
}
}

View File

@@ -17,7 +17,6 @@ import org.neo4j.ogm.model.Result;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.examples.galaxy.domain.World;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.stereotype.Repository;
/**
@@ -27,12 +26,12 @@ import org.springframework.stereotype.Repository;
@Repository
public interface WorldRepository extends GraphRepository<World> {
@Query("MATCH (n:World) SET n.updated=timestamp()")
void touchAllWorlds();
@Query("MATCH (n:World) SET n.updated=timestamp()")
void touchAllWorlds();
@Query("MATCH (n:World) SET n.updated=timestamp()")
Result touchAllWorldsWithStatistics();
@Query("MATCH (n:World) SET n.updated=timestamp()")
Result touchAllWorldsWithStatistics();
World findByName(String name);
World findByName(String name);
}

View File

@@ -36,11 +36,9 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional
public class GalaxyService {
@Autowired
private WorldRepository worldRepository;
@Autowired private WorldRepository worldRepository;
@Autowired
Session session;
@Autowired Session session;
public long getNumberOfWorlds() {
return worldRepository.count();
@@ -89,13 +87,13 @@ public class GalaxyService {
mars.addRocketRouteTo(earth);
// todo: handle bi-directional automatically
//earth.addRocketRouteTo(mars);
// earth.addRocketRouteTo(mars);
// this is a bit silly
worldRepository.save(mars);
// todo: handle-bidirectional automatically
//worldRepository.save(earth);
// worldRepository.save(earth);
worlds.add(earth);
worlds.add(mars);
@@ -163,7 +161,6 @@ public class GalaxyService {
return session.loadAll(World.class, new Filter(propertyName, propertyValue), depth);
}
public Iterable<World> findAllWorlds(Pagination paging) {
return session.loadAll(World.class, paging, 0);
}

View File

@@ -28,7 +28,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
* @author Mark Angrish
*/
@Configuration
@ComponentScan(basePackageClasses = {AdultService.class})
@ComponentScan(basePackageClasses = { AdultService.class })
@EnableNeo4jRepositories("org.springframework.data.neo4j.examples.jsr303.repo")
@EnableTransactionManagement
public class JSR303Context {

View File

@@ -35,18 +35,16 @@ import org.springframework.web.context.WebApplicationContext;
* @author Vince Bickers
* @author Mark Angrish
*/
@ContextConfiguration(classes = {WebConfiguration.class, JSR303Context.class})
@ContextConfiguration(classes = { WebConfiguration.class, JSR303Context.class })
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class JSR303IT extends MultiDriverTestClass {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private AdultService service;
@Autowired private AdultService service;
@Autowired
WebApplicationContext wac;
@Autowired WebApplicationContext wac;
private MockMvc mockMvc;
@@ -61,11 +59,7 @@ public class JSR303IT extends MultiDriverTestClass {
Adult adult = new Adult("Peter", 18);
String json = objectMapper.writeValueAsString(adult);
mockMvc.perform(
post("/adults")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isOk());
mockMvc.perform(post("/adults").contentType(MediaType.APPLICATION_JSON).content(json)).andExpect(status().isOk());
}
@Test
@@ -74,10 +68,7 @@ public class JSR303IT extends MultiDriverTestClass {
Adult adult = new Adult("Peter", 16);
String json = objectMapper.writeValueAsString(adult);
mockMvc.perform(
post("/adults")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
mockMvc.perform(post("/adults").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isBadRequest());
}
@@ -87,10 +78,7 @@ public class JSR303IT extends MultiDriverTestClass {
Adult adult = new Adult(null, 21);
String json = objectMapper.writeValueAsString(adult);
mockMvc.perform(
post("/adults")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
mockMvc.perform(post("/adults").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isBadRequest());
}
@@ -100,10 +88,7 @@ public class JSR303IT extends MultiDriverTestClass {
Adult adult = new Adult("A", 21);
String json = objectMapper.writeValueAsString(adult);
mockMvc.perform(
post("/adults")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
mockMvc.perform(post("/adults").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isBadRequest());
}
}

View File

@@ -24,13 +24,13 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @author Vince Bickers
*/
@Configuration
@ComponentScan({"org.springframework.data.neo4j.examples.jsr303.controller"})
@ComponentScan({ "org.springframework.data.neo4j.examples.jsr303.controller" })
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Bean(name="validator")
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
@Bean(name = "validator")
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}

View File

@@ -13,16 +13,21 @@
package org.springframework.data.neo4j.examples.jsr303.controller;
import javax.validation.Valid;
import javax.validation.ValidationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.examples.jsr303.domain.Adult;
import org.springframework.data.neo4j.examples.jsr303.service.AdultService;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.ValidationException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* @author Vince Bickers
@@ -30,22 +35,21 @@ import javax.validation.ValidationException;
@Controller
public class AdultController {
@Autowired
private AdultService service;
@Autowired private AdultService service;
@RequestMapping(value = "/adults", method = RequestMethod.POST, consumes = "application/json")
@ResponseBody
public Adult create (@Valid @RequestBody Adult entity, BindingResult bindingResult) {
// in practice we'd do a bit more than this...
if (bindingResult.hasErrors()) {
throw new ValidationException("oops");
}
return service.save(entity);
}
@RequestMapping(value = "/adults", method = RequestMethod.POST, consumes = "application/json")
@ResponseBody
public Adult create(@Valid @RequestBody Adult entity, BindingResult bindingResult) {
// in practice we'd do a bit more than this...
if (bindingResult.hasErrors()) {
throw new ValidationException("oops");
}
return service.save(entity);
}
@ExceptionHandler(ValidationException.class)
@ResponseBody
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public void handleException(ValidationException ve) { }
@ExceptionHandler(ValidationException.class)
@ResponseBody
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public void handleException(ValidationException ve) {}
}

View File

@@ -27,20 +27,15 @@ import org.neo4j.ogm.annotation.NodeEntity;
@NodeEntity
public class Adult {
@GraphId
private Long id;
@GraphId private Long id;
@NotNull @Size(min = 2, max = 50)
private String name;
@NotNull @Size(min = 2, max = 50) private String name;
@Min(18)
private Integer age;
@Min(18) private Integer age;
@AssertTrue
private boolean votingAge;
@AssertTrue private boolean votingAge;
public Adult() {
}
public Adult() {}
public Adult(String name, Integer age) {
this.name = name;
@@ -48,7 +43,6 @@ public class Adult {
this.votingAge = true;
}
public String getName() {
return name;
}

View File

@@ -21,5 +21,4 @@ import org.springframework.stereotype.Repository;
* @author Vince Bickers
*/
@Repository
public interface AdultRepository extends Neo4jRepository<Adult, Long> {
}
public interface AdultRepository extends Neo4jRepository<Adult, Long> {}

View File

@@ -24,10 +24,9 @@ import org.springframework.stereotype.Service;
@Service
public class AdultService {
@Autowired
private AdultRepository repository;
@Autowired private AdultRepository repository;
public Adult save(Adult adult) {
return repository.save(adult);
}
public Adult save(Adult adult) {
return repository.save(adult);
}
}

View File

@@ -15,14 +15,18 @@ package org.springframework.data.neo4j.examples.movies;
import static org.junit.Assert.*;
import static org.neo4j.ogm.testutil.GraphTestUtils.*;
import static org.springframework.data.repository.query.parser.Part.Type.*;
import java.util.*;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang.ArrayUtils;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
@@ -38,8 +42,20 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.neo4j.examples.movies.context.MoviesContext;
import org.springframework.data.neo4j.examples.movies.domain.*;
import org.springframework.data.neo4j.examples.movies.repo.*;
import org.springframework.data.neo4j.examples.movies.domain.Actor;
import org.springframework.data.neo4j.examples.movies.domain.Cinema;
import org.springframework.data.neo4j.examples.movies.domain.Genre;
import org.springframework.data.neo4j.examples.movies.domain.Movie;
import org.springframework.data.neo4j.examples.movies.domain.ReleasedMovie;
import org.springframework.data.neo4j.examples.movies.domain.TempMovie;
import org.springframework.data.neo4j.examples.movies.domain.User;
import org.springframework.data.neo4j.examples.movies.repo.AbstractAnnotatedEntityRepository;
import org.springframework.data.neo4j.examples.movies.repo.AbstractEntityRepository;
import org.springframework.data.neo4j.examples.movies.repo.ActorRepository;
import org.springframework.data.neo4j.examples.movies.repo.CinemaRepository;
import org.springframework.data.neo4j.examples.movies.repo.RatingRepository;
import org.springframework.data.neo4j.examples.movies.repo.TempMovieRepository;
import org.springframework.data.neo4j.examples.movies.repo.UserRepository;
import org.springframework.data.neo4j.examples.movies.service.UserService;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -54,7 +70,7 @@ import org.springframework.transaction.support.TransactionTemplate;
* @author Vince Bickers
* @author Mark Angrish
*/
@ContextConfiguration(classes = {MoviesContext.class})
@ContextConfiguration(classes = { MoviesContext.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class MoviesIntegrationIT extends MultiDriverTestClass {
@@ -62,26 +78,16 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
private static GraphDatabaseService graphDatabaseService;
@Autowired
PlatformTransactionManager platformTransactionManager;
@Autowired
private Session session;
@Autowired
private UserRepository userRepository;
@Autowired
private UserService userService;
@Autowired
private CinemaRepository cinemaRepository;
@Autowired
private AbstractAnnotatedEntityRepository abstractAnnotatedEntityRepository;
@Autowired
private AbstractEntityRepository abstractEntityRepository;
@Autowired
private TempMovieRepository tempMovieRepository;
@Autowired
private ActorRepository actorRepository;
@Autowired
private RatingRepository ratingRepository;
@Autowired PlatformTransactionManager platformTransactionManager;
@Autowired private Session session;
@Autowired private UserRepository userRepository;
@Autowired private UserService userService;
@Autowired private CinemaRepository cinemaRepository;
@Autowired private AbstractAnnotatedEntityRepository abstractAnnotatedEntityRepository;
@Autowired private AbstractEntityRepository abstractEntityRepository;
@Autowired private TempMovieRepository tempMovieRepository;
@Autowired private ActorRepository actorRepository;
@Autowired private RatingRepository ratingRepository;
private TransactionTemplate transactionTemplate;
@@ -112,7 +118,6 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
assertSameGraph(graphDatabaseService, "CREATE (u:User:Person)");
}
@Test
public void shouldSaveReleasedMovie() {
@@ -125,8 +130,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
abstractAnnotatedEntityRepository.save(releasedMovie);
assertSameGraph(graphDatabaseService,
"CREATE (m:ReleasedMovie:AbstractAnnotatedEntity {cinemaRelease:'1994-09-10T00:00:00.000Z'," +
"cannesRelease:768700800000,title:'Pulp Fiction'})");
"CREATE (m:ReleasedMovie:AbstractAnnotatedEntity {cinemaRelease:'1994-09-10T00:00:00.000Z',"
+ "cannesRelease:768700800000,title:'Pulp Fiction'})");
}
@Test
@@ -146,14 +151,14 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
public void shouldSaveMovie() {
Movie movie = new Movie("Pulp Fiction");
movie.setTags(new String[]{"cool", "classic"});
movie.setImage(new byte[]{1, 2, 3});
movie.setTags(new String[] { "cool", "classic" });
movie.setImage(new byte[] { 1, 2, 3 });
abstractEntityRepository.save(movie);
// byte arrays have to be transferred with a JSON-supported format. Base64 is the default.
assertSameGraph(graphDatabaseService, "CREATE (m:Movie {name:'Pulp Fiction', tags:['cool','classic'], " +
"image:'AQID'})");
assertSameGraph(graphDatabaseService,
"CREATE (m:Movie {name:'Pulp Fiction', tags:['cool','classic'], " + "image:'AQID'})");
}
@Test
@@ -171,12 +176,10 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE (:User:Person {name:'Michal'})," +
"(:User:Person {name:'Vince'})," +
"(:User:Person {name:'Adam'})");
assertSameGraph(graphDatabaseService,
"CREATE (:User:Person {name:'Michal'})," + "(:User:Person {name:'Vince'})," + "(:User:Person {name:'Adam'})");
}
@Test
public void shouldSaveUsers2() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@@ -192,9 +195,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE (:User:Person {name:'Michal'})," +
"(:User:Person {name:'Vince'})," +
"(:User:Person {name:'Adam'})");
assertSameGraph(graphDatabaseService,
"CREATE (:User:Person {name:'Michal'})," + "(:User:Person {name:'Vince'})," + "(:User:Person {name:'Adam'})");
}
@Test
@@ -211,16 +213,15 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
assertSameGraph(graphDatabaseService, "CREATE (u:User:Person {name:'Adam'})");
}
@Test
@Ignore // FIXME
@Ignore // FIXME
// this test expects the session/tx to check for dirty objects, which it currently does not do
// you must save objects explicitly.
public void shouldUpdateUserUsingTransactionalService() {
User user = new User("Michal");
userRepository.save(user);
userService.updateUser(user, "Adam"); //notice userRepository.save(..) isn't called,
userService.updateUser(user, "Adam"); // notice userRepository.save(..) isn't called,
// not even in the service impl!
assertSameGraph(graphDatabaseService, "CREATE (u:User {name:'Adam'})");
@@ -292,7 +293,6 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
}
@Test
public void shouldHandleMultipleConcurrentRequests() throws InterruptedException, Neo4jFailedToStartException {
@@ -319,7 +319,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
@Test(expected = DataAccessException.class)
public void shouldInterceptOGMExceptions() {
ratingRepository.findAll(0); // ratings are REs and must be found to at least depth 1 in order to get the start and end nodes
ratingRepository.findAll(0); // ratings are REs and must be found to at least depth 1 in order to get the start and
// end nodes
}
@Test
@@ -329,7 +330,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
userRepository.save(user);
assertSameGraph(graphDatabaseService, "CREATE (u:User:Person {name:'Michal'})-[:INTERESTED]->(g:Genre {name:'Drama'})");
assertSameGraph(graphDatabaseService,
"CREATE (u:User:Person {name:'Michal'})-[:INTERESTED]->(g:Genre {name:'Drama'})");
}
@Test
@@ -341,14 +343,10 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
userRepository.save(user);
assertSameGraph(graphDatabaseService, "CREATE " +
"(u:User:Person {name:'Michal'})," +
"(g1:Genre {name:'Drama'})," +
"(g2:Genre {name:'Historical'})," +
"(g3:Genre {name:'Thriller'})," +
"(u)-[:INTERESTED]->(g1)," +
"(u)-[:INTERESTED]->(g2)," +
"(u)-[:INTERESTED]->(g3)");
assertSameGraph(graphDatabaseService,
"CREATE " + "(u:User:Person {name:'Michal'})," + "(g1:Genre {name:'Drama'}),"
+ "(g2:Genre {name:'Historical'})," + "(g3:Genre {name:'Thriller'})," + "(u)-[:INTERESTED]->(g1),"
+ "(u)-[:INTERESTED]->(g2)," + "(u)-[:INTERESTED]->(g3)");
}
@Test
@@ -358,7 +356,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
userRepository.save(user, 1);
assertSameGraph(graphDatabaseService, "CREATE (u:User:Person {name:'Michal'})-[:INTERESTED]->(g:Genre {name:'Drama'})");
assertSameGraph(graphDatabaseService,
"CREATE (u:User:Person {name:'Michal'})-[:INTERESTED]->(g:Genre {name:'Drama'})");
}
@Test
@@ -379,15 +378,11 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE " +
"(m:User:Person {name:'Michal'})," +
"(v:User:Person {name:'Vince'})," +
"(g:Genre {name:'Drama'})," +
"(m)-[:INTERESTED]->(g)," +
"(v)-[:INTERESTED]->(g)");
assertSameGraph(graphDatabaseService,
"CREATE " + "(m:User:Person {name:'Michal'})," + "(v:User:Person {name:'Vince'})," + "(g:Genre {name:'Drama'}),"
+ "(m)-[:INTERESTED]->(g)," + "(v)-[:INTERESTED]->(g)");
}
@Test
public void shouldSaveUserButNotGenre() {
User user = new User("Michal");
@@ -416,13 +411,10 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE " +
"(m:User:Person {name:'Michal'})," +
"(g:Genre {name:'New Drama'})," +
"(m)-[:INTERESTED]->(g)");
assertSameGraph(graphDatabaseService,
"CREATE " + "(m:User:Person {name:'Michal'})," + "(g:Genre {name:'New Drama'})," + "(m)-[:INTERESTED]->(g)");
}
@Test
public void shouldRemoveGenreFromUser() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@@ -440,9 +432,7 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE " +
"(m:User:Person {name:'Michal'})," +
"(g:Genre {name:'Drama'})");
assertSameGraph(graphDatabaseService, "CREATE " + "(m:User:Person {name:'Michal'})," + "(g:Genre {name:'Drama'})");
}
@Test
@@ -460,12 +450,9 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE " +
"(m:User:Person {name:'Michal'})," +
"(g:Genre {name:'Drama'})");
assertSameGraph(graphDatabaseService, "CREATE " + "(m:User:Person {name:'Michal'})," + "(g:Genre {name:'Drama'})");
}
@Test
public void shouldAddNewVisitorToCinema() {
Cinema cinema = new Cinema("Odeon");
@@ -473,10 +460,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
cinemaRepository.save(cinema);
assertSameGraph(graphDatabaseService, "CREATE " +
"(m:User:Person {name:'Michal'})," +
"(c:Theatre {name:'Odeon', capacity:0})," +
"(m)-[:VISITED]->(c)");
assertSameGraph(graphDatabaseService, "CREATE " + "(m:User:Person {name:'Michal'}),"
+ "(c:Theatre {name:'Odeon', capacity:0})," + "(m)-[:VISITED]->(c)");
}
@Test
@@ -494,10 +479,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
}
});
assertSameGraph(graphDatabaseService, "CREATE " +
"(m:User:Person {name:'Michal'})," +
"(c:Theatre {name:'Odeon', capacity:0})," +
"(m)-[:VISITED]->(c)");
assertSameGraph(graphDatabaseService, "CREATE " + "(m:User:Person {name:'Michal'}),"
+ "(c:Theatre {name:'Odeon', capacity:0})," + "(m)-[:VISITED]->(c)");
}
@Test
@@ -512,9 +495,11 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
});
try {
assertSameGraph(graphDatabaseService, "CREATE (m:User {name:'Michal'})-[:FRIEND_OF]->(a:User:Person {name:'Adam'})");
assertSameGraph(graphDatabaseService,
"CREATE (m:User {name:'Michal'})-[:FRIEND_OF]->(a:User:Person {name:'Adam'})");
} catch (AssertionError error) {
assertSameGraph(graphDatabaseService, "CREATE (m:User:Person {name:'Michal'})<-[:FRIEND_OF]-(a:User:Person {name:'Adam'})");
assertSameGraph(graphDatabaseService,
"CREATE (m:User:Person {name:'Michal'})<-[:FRIEND_OF]-(a:User:Person {name:'Adam'})");
}
}
@@ -559,8 +544,8 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
User michal = ((Iterable<User>) findByProperty(User.class, "name", "Michal")).iterator().next();
assertSameGraph(graphDatabaseService, "CREATE (u:User:Person {name:'Michal'})-[:RATED {stars:5, " +
"comment:'Best movie ever', ratingTimestamp:0}]->(m:Movie {name:'Pulp Fiction'})");
assertSameGraph(graphDatabaseService, "CREATE (u:User:Person {name:'Michal'})-[:RATED {stars:5, "
+ "comment:'Best movie ever', ratingTimestamp:0}]->(m:Movie {name:'Pulp Fiction'})");
}
@Test
@@ -570,15 +555,16 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
TempMovie movie = new TempMovie("Pulp Fiction");
//Save the movie
// Save the movie
movie = tempMovieRepository.save(movie);
//Create a new user and rate an existing movie
// Create a new user and rate an existing movie
User user = new User("Michal");
user.rate(movie, 5, "Best movie ever");
userRepository.save(user);
TempMovie tempMovie = ((Iterable<TempMovie>) findByProperty(TempMovie.class, "name", "Pulp Fiction")).iterator().next();
TempMovie tempMovie = ((Iterable<TempMovie>) findByProperty(TempMovie.class, "name", "Pulp Fiction")).iterator()
.next();
assertEquals(1, tempMovie.getRatings().size());
}
});
@@ -594,10 +580,10 @@ public class MoviesIntegrationIT extends MultiDriverTestClass {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
TempMovie movie = new TempMovie("Pulp Fiction");
//Save the movie
// Save the movie
movie = tempMovieRepository.save(movie);
//Create a new user and rate an existing movie
// Create a new user and rate an existing movie
User user = new User("Michal");
user.rate(movie, 5, "Best movie ever");
userRepository.save(user);

View File

@@ -27,7 +27,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
* @author Mark Angrish
*/
@Configuration
@ComponentScan({"org.springframework.data.neo4j.examples.movies.service"})
@ComponentScan({ "org.springframework.data.neo4j.examples.movies.service" })
@EnableNeo4jRepositories("org.springframework.data.neo4j.examples.movies.repo")
@EnableTransactionManagement
public class MoviesContext {

View File

@@ -22,6 +22,5 @@ import org.neo4j.ogm.annotation.NodeEntity;
@NodeEntity
public abstract class AbstractAnnotatedEntity {
@GraphId
Long nodeId;
@GraphId Long nodeId;
}

View File

@@ -19,9 +19,9 @@ package org.springframework.data.neo4j.examples.movies.domain;
*/
public abstract class AbstractEntity {
Long id;
Long id;
public Long getId() {
return id;
}
public Long getId() {
return id;
}
}

View File

@@ -13,40 +13,37 @@
package org.springframework.data.neo4j.examples.movies.domain;
import org.neo4j.ogm.annotation.GraphId;
/**
* @author Michal Bachman
*/
public class Actor{
public class Actor {
@GraphId
Long nodeId;
String id;
String name;
@GraphId Long nodeId;
String id;
String name;
public Actor() {
}
public Actor() {}
public Actor(String id, String name) {
this.id = id;
this.name = name;
}
public Actor(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -13,13 +13,13 @@
package org.springframework.data.neo4j.examples.movies.domain;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.annotation.Relationship;
import java.util.HashSet;
import java.util.Set;
/**
* @author Michal Bachman
* @author Luanne Misquitta
@@ -31,19 +31,15 @@ public class Cinema {
private Long id;
private String name;
@Property(name = "city")
private String location;
@Property(name = "city") private String location;
@Relationship(type = "VISITED", direction = Relationship.INCOMING)
private Set<User> visited = new HashSet<>();
@Relationship(type = "VISITED", direction = Relationship.INCOMING) private Set<User> visited = new HashSet<>();
@Relationship(type = "BLOCKBUSTER", direction = Relationship.OUTGOING)
private TempMovie blockbusterOfTheWeek;
@Relationship(type = "BLOCKBUSTER", direction = Relationship.OUTGOING) private TempMovie blockbusterOfTheWeek;
private int capacity;
public Cinema() {
}
public Cinema() {}
public Cinema(String name) {
this.name = name;
@@ -93,8 +89,10 @@ public class Cinema {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Cinema cinema = (Cinema) o;

View File

@@ -20,6 +20,5 @@ public class Director extends Person {
private Long id;
public Director() {
}
public Director() {}
}

View File

@@ -18,25 +18,24 @@ package org.springframework.data.neo4j.examples.movies.domain;
*/
public class Genre {
private Long id;
private String name;
private Long id;
private String name;
public Genre() {
}
public Genre() {}
public Genre(String name) {
this.name = name;
}
public Genre(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -18,34 +18,33 @@ package org.springframework.data.neo4j.examples.movies.domain;
*/
public class Movie extends AbstractEntity {
private String name;
private String[] tags;
private byte[] image;
private String name;
private String[] tags;
private byte[] image;
public Movie() {
}
public Movie() {}
public Movie(String name) {
this.name = name;
}
public Movie(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public String[] getTags() {
return tags;
}
public String[] getTags() {
return tags;
}
public void setTags(String[] tags) {
this.tags = tags;
}
public void setTags(String[] tags) {
this.tags = tags;
}
public byte[] getImage() {
return image;
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
public void setImage(byte[] image) {
this.image = image;
}
}

View File

@@ -21,7 +21,6 @@ public class Person {
private String name;
public String getName() {
return name;
}
@@ -36,8 +35,10 @@ public class Person {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Person person = (Person) o;

View File

@@ -21,77 +21,75 @@ import org.neo4j.ogm.annotation.StartNode;
* @author Michal Bachman
*/
@RelationshipEntity(type = "RATED")
public class Rating implements Comparable{
private Long id;
public class Rating implements Comparable {
private Long id;
@StartNode
private User user;
@EndNode
private TempMovie movie;
private int stars;
private String comment;
@StartNode private User user;
@EndNode private TempMovie movie;
private int stars;
private String comment;
private long ratingTimestamp;
private long ratingTimestamp;
public Rating() {}
public Rating() {}
public Rating(User user, TempMovie movie, int stars, String comment) {
this.user = user;
this.movie = movie;
this.stars = stars;
this.comment = comment;
}
public Rating(User user, TempMovie movie, int stars, String comment) {
this.user = user;
this.movie = movie;
this.stars = stars;
this.comment = comment;
}
public Long getId() {
return id;
}
public Long getId() {
return id;
}
public void setUser(User user) {
this.user = user;
}
public void setUser(User user) {
this.user = user;
}
public void setMovie(TempMovie movie) {
this.movie = movie;
}
public void setMovie(TempMovie movie) {
this.movie = movie;
}
public void setStars(int stars) {
this.stars = stars;
}
public void setStars(int stars) {
this.stars = stars;
}
public void setComment(String comment) {
this.comment = comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public User getUser() {
return user;
}
public User getUser() {
return user;
}
public TempMovie getMovie() {
return movie;
}
public TempMovie getMovie() {
return movie;
}
public int getStars() {
return stars;
}
public int getStars() {
return stars;
}
public String getComment() {
return comment;
}
public String getComment() {
return comment;
}
public long getRatingTimestamp() {
return ratingTimestamp;
}
public long getRatingTimestamp() {
return ratingTimestamp;
}
public void setRatingTimestamp(long ratingTimestamp) {
this.ratingTimestamp = ratingTimestamp;
}
public void setRatingTimestamp(long ratingTimestamp) {
this.ratingTimestamp = ratingTimestamp;
}
@Override
public int compareTo(Object o) {
Rating other = (Rating) o;
if (stars == ((Rating) o).getStars()) {
return getUser().getName().compareTo(other.getUser().getName());
}
return stars - other.getStars();
}
@Override
public int compareTo(Object o) {
Rating other = (Rating) o;
if (stars == ((Rating) o).getStars()) {
return getUser().getName().compareTo(other.getUser().getName());
}
return stars - other.getStars();
}
}

View File

@@ -13,43 +13,40 @@
package org.springframework.data.neo4j.examples.movies.domain;
import java.util.Date;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.annotation.typeconversion.DateLong;
import java.util.Date;
/**
* @author Michal Bachman
*/
//the fields here will move to Movie, this separate class exists temporarily after its tests pass
// the fields here will move to Movie, this separate class exists temporarily after its tests pass
public class ReleasedMovie extends AbstractAnnotatedEntity {
private String title;
private String title;
@Property(name = "cinemaRelease")
private Date released;
@Property(name = "cinemaRelease") private Date released;
@DateLong
private Date cannesRelease;
@DateLong private Date cannesRelease;
public ReleasedMovie() {
}
public ReleasedMovie() {}
public ReleasedMovie(String title, Date released, Date cannesRelease) {
this.title = title;
this.released = released;
this.cannesRelease = cannesRelease;
}
public ReleasedMovie(String title, Date released, Date cannesRelease) {
this.title = title;
this.released = released;
this.cannesRelease = cannesRelease;
}
public String getTitle() {
return title;
}
public String getTitle() {
return title;
}
public Date getReleased() {
return released;
}
public Date getReleased() {
return released;
}
public Date getCannesRelease() {
return cannesRelease;
}
public Date getCannesRelease() {
return cannesRelease;
}
}

View File

@@ -13,40 +13,38 @@
package org.springframework.data.neo4j.examples.movies.domain;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
/**
* @author Michal Bachman
* @author Luanne Misquitta
*/
//todo merge with movie when tests fixed
// todo merge with movie when tests fixed
@NodeEntity(label = "Movie")
public class TempMovie extends AbstractEntity {
private String name;
@Relationship(type = "RATED", direction = Relationship.INCOMING)
private Set<Rating> ratings = new HashSet<>();
private String name;
@Relationship(type = "RATED", direction = Relationship.INCOMING) private Set<Rating> ratings = new HashSet<>();
public TempMovie() {
}
public TempMovie() {}
public TempMovie(String name) {
this.name = name;
}
public TempMovie(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public void addRating(Rating rating) {
ratings.add(rating);
}
public void addRating(Rating rating) {
ratings.add(rating);
}
public Set<Rating> getRatings() {
return ratings;
}
public Set<Rating> getRatings() {
return ratings;
}
}

View File

@@ -13,80 +13,76 @@
package org.springframework.data.neo4j.examples.movies.domain;
import org.neo4j.ogm.annotation.Relationship;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.neo4j.ogm.annotation.Relationship;
/**
* @author Michal Bachman
* @author Luanne Misquitta
*/
public class User extends Person{
public class User extends Person {
private String middleName;
private String surname;
private String middleName;
private String surname;
private Collection<Genre> interested = new HashSet<>();
private Collection<Genre> interested = new HashSet<>();
@Relationship(type = "FRIEND_OF", direction = Relationship.UNDIRECTED)
private Collection<User> friends = new HashSet<>();
@Relationship(type = "FRIEND_OF",
direction = Relationship.UNDIRECTED) private Collection<User> friends = new HashSet<>();
@Relationship(type = "RATED")
private Set<Rating> ratings = new HashSet<>();
@Relationship(type = "RATED") private Set<Rating> ratings = new HashSet<>();
public User() {
}
public User() {}
public User(String name) {
setName(name);
}
public User(String name) {
setName(name);
}
public User(String name, String surname) {
setName(name);
this.surname = surname;
}
public User(String name, String surname) {
setName(name);
this.surname = surname;
}
public void interestedIn(Genre genre) {
interested.add(genre);
}
public void interestedIn(Genre genre) {
interested.add(genre);
}
public void notInterestedIn(Genre genre) {
interested.remove(genre);
}
public void notInterestedIn(Genre genre) {
interested.remove(genre);
}
public void befriend(User user) {
friends.add(user);
user.friends.add(this);
}
public void befriend(User user) {
friends.add(user);
user.friends.add(this);
}
public Rating rate(TempMovie movie, int stars, String comment) {
Rating rating = new Rating(this, movie, stars, comment);
movie.addRating(rating);
ratings.add(rating);
return rating;
}
public Rating rate(TempMovie movie, int stars, String comment) {
Rating rating = new Rating(this, movie, stars, comment);
movie.addRating(rating);
ratings.add(rating);
return rating;
}
public Collection<User> getFriends() {
return friends;
}
public Collection<User> getFriends() {
return friends;
}
public String getMiddleName() {
return middleName;
}
public String getMiddleName()
{
return middleName;
}
public Set<Rating> getRatings() {
return ratings;
}
public Set<Rating> getRatings() {
return ratings;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getSurname() {
return surname;
}
public String getSurname() {
return surname;
}
}

View File

@@ -23,25 +23,24 @@ import org.springframework.data.neo4j.annotation.QueryResult;
@QueryResult
public class CinemaQueryResult {
private Long id;
private String name;
private Long id;
private String name;
public CinemaQueryResult() {
}
public CinemaQueryResult() {}
public Long getId() {
return id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -23,12 +23,12 @@ import org.springframework.data.neo4j.annotation.QueryResult;
@QueryResult
public interface CinemaQueryResultInterface {
Long getId();
Long getId();
void setId(Long id);
void setId(Long id);
String getName();
String getName();
void setName(String name);
void setName(String name);
}

View File

@@ -21,8 +21,7 @@ public class CinemaQueryResultInterfaceImpl implements CinemaQueryResultInterfac
private Long id;
private String name;
public CinemaQueryResultInterfaceImpl() {
}
public CinemaQueryResultInterfaceImpl() {}
public Long getId() {
return id;

View File

@@ -31,41 +31,40 @@ import org.springframework.data.neo4j.examples.movies.domain.User;
@QueryResult
public class EntityWrappingQueryResult {
private User user;
private Set<User> friends;
private List<Rating> ratings;
private TempMovie[] movies;
private float avgRating;
private List<Float> allRatings;
private Collection<Map<String, Object>> literalMap;
private User user;
private Set<User> friends;
private List<Rating> ratings;
private TempMovie[] movies;
private float avgRating;
private List<Float> allRatings;
private Collection<Map<String, Object>> literalMap;
public User getUser() {
return user;
}
public User getUser() {
return user;
}
public Set<User> getFriends() {
return friends;
}
public Set<User> getFriends() {
return friends;
}
public List<Rating> getRatings() {
return ratings;
}
public List<Rating> getRatings() {
return ratings;
}
public float getAvgRating() {
return avgRating;
}
public float getAvgRating() {
return avgRating;
}
public TempMovie[] getMovies() {
return movies;
}
public TempMovie[] getMovies() {
return movies;
}
public List<Float> getAllRatings() {
return allRatings;
}
public List<Float> getAllRatings() {
return allRatings;
}
public Collection<Map<String, Object>> getLiteralMap() {
return literalMap;
}
public Collection<Map<String, Object>> getLiteralMap() {
return literalMap;
}
}

View File

@@ -15,6 +15,6 @@ package org.springframework.data.neo4j.examples.movies.domain.queryresult;
public enum Gender {
FEMALE, MALE;
FEMALE, MALE;
}

View File

@@ -13,11 +13,11 @@
package org.springframework.data.neo4j.examples.movies.domain.queryresult;
import org.springframework.data.neo4j.annotation.QueryResult;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.springframework.data.neo4j.annotation.QueryResult;
/**
* A {@link QueryResult} that contains rich types.
*
@@ -27,24 +27,24 @@ import java.math.BigInteger;
@QueryResult
public class RichUserQueryResult {
private Gender userGender; // should be handled by default type conversion
private String userName;
private BigInteger userAccount;
private BigDecimal[] userDeposits;
private Gender userGender; // should be handled by default type conversion
private String userName;
private BigInteger userAccount;
private BigDecimal[] userDeposits;
public Gender getUserGender() {
return userGender;
}
public Gender getUserGender() {
return userGender;
}
public String getUserName() {
return userName;
}
public String getUserName() {
return userName;
}
public BigInteger getUserAccount() {
return userAccount;
}
public BigInteger getUserAccount() {
return userAccount;
}
public BigDecimal[] getUserDeposits() {
return userDeposits;
}
}
public BigDecimal[] getUserDeposits() {
return userDeposits;
}
}

View File

@@ -19,93 +19,91 @@ import org.springframework.data.neo4j.annotation.QueryResult;
import org.springframework.data.neo4j.examples.movies.repo.UserRepository;
/**
* Example POJO {@link QueryResult} to test mapping onto arbitrary objects, even for properties that are on the nodes but not in
* the entity classes.
* Example POJO {@link QueryResult} to test mapping onto arbitrary objects, even for properties that are on the nodes
* but not in the entity classes.
*
* @see UserRepository
*
* @author Adam George
* @author Luanne Misquitta
*/
@QueryResult
public class UserQueryResult {
private Long id;
Long userId;
private String userName;
private int age;
private Long id;
Long userId;
private String userName;
private int age;
UserQueryResult() {
// default constructor for OGM
}
UserQueryResult() {
// default constructor for OGM
}
public UserQueryResult(String name, int age) {
this.userName = name;
this.age = age;
}
public UserQueryResult(String name, int age) {
this.userName = name;
this.age = age;
}
public String getUserName() {
return userName;
}
public String getUserName() {
return userName;
}
public void setUserName(String name) {
this.userName = name;
}
public void setUserName(String name) {
this.userName = name;
}
@Property(name = "user.age")
public int getAge() {
return age;
}
@Property(name = "user.age")
public int getAge() {
return age;
}
@Property(name = "user.age")
public void setAge(int age) {
this.age = age;
}
@Property(name = "user.age")
public void setAge(int age) {
this.age = age;
}
public Long getUserId() {
return userId;
}
public Long getUserId() {
return userId;
}
public Long getId() {
return id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public int hashCode() {
final int prime = 23;
int result = 1;
result = prime * result + age;
result = prime * result + ((userName == null) ? 0 : userName.hashCode());
return result;
}
@Override
public int hashCode() {
final int prime = 23;
int result = 1;
result = prime * result + age;
result = prime * result + ((userName == null) ? 0 : userName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserQueryResult other = (UserQueryResult) obj;
if (age != other.age)
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserQueryResult other = (UserQueryResult) obj;
if (age != other.age)
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}

View File

@@ -19,19 +19,19 @@ import org.springframework.data.neo4j.examples.movies.domain.User;
import org.springframework.data.neo4j.examples.movies.repo.UserRepository;
/**
* Example interface annotated with {@link QueryResult} to test mapping onto proxied objects, where only getter methods are
* needed to define the mapped result columns.
* Example interface annotated with {@link QueryResult} to test mapping onto proxied objects, where only getter methods
* are needed to define the mapped result columns.
*
* @see UserRepository
*/
@QueryResult
public interface UserQueryResultInterface {
@Property(name = "user.name")
String getNameOfUser();
@Property(name = "user.name")
String getNameOfUser();
int getAgeOfUser();
int getAgeOfUser();
User getUser();
User getUser();
}

View File

@@ -21,5 +21,4 @@ import org.springframework.stereotype.Repository;
* @author Michal Bachman
*/
@Repository
public interface AbstractAnnotatedEntityRepository extends Neo4jRepository<AbstractAnnotatedEntity, Long> {
}
public interface AbstractAnnotatedEntityRepository extends Neo4jRepository<AbstractAnnotatedEntity, Long> {}

View File

@@ -21,5 +21,4 @@ import org.springframework.stereotype.Repository;
* @author Michal Bachman
*/
@Repository
public interface AbstractEntityRepository extends Neo4jRepository<AbstractEntity, Long> {
}
public interface AbstractEntityRepository extends Neo4jRepository<AbstractEntity, Long> {}

View File

@@ -16,10 +16,7 @@ package org.springframework.data.neo4j.examples.movies.repo;
import org.springframework.data.neo4j.examples.movies.domain.Actor;
import org.springframework.data.neo4j.repository.Neo4jRepository;
/**
* @author Michal Bachman
*/
public interface ActorRepository extends Neo4jRepository<Actor, Long> {
}
public interface ActorRepository extends Neo4jRepository<Actor, Long> {}

View File

@@ -93,7 +93,8 @@ public interface CinemaRepository extends Neo4jRepository<Cinema, Long> {
@Query(value = "MATCH (n:Theatre) RETURN n ORDER BY n.name", countQuery = "MATCH (n:Theatre) return count(*)")
Page<Cinema> getPagedCinemasWithPageCount(Pageable pageable);
@Query(value = "MATCH (n:Theatre {city:{city}}) RETURN n ORDER BY n.name", countQuery = "MATCH (n:Theatre {city:{city}}) return count(*)")
@Query(value = "MATCH (n:Theatre {city:{city}}) RETURN n ORDER BY n.name",
countQuery = "MATCH (n:Theatre {city:{city}}) return count(*)")
Page<Cinema> getPagedCinemasByCityWithPageCount(@Param("city") String city, Pageable pageable);
@Query("MATCH (n:Theatre) RETURN n")

View File

@@ -21,5 +21,4 @@ import org.springframework.stereotype.Repository;
* @author Michal Bachman
*/
@Repository
public interface GenreRepository extends Neo4jRepository<Genre, Long> {
}
public interface GenreRepository extends Neo4jRepository<Genre, Long> {}

Some files were not shown because too many files have changed in this diff Show More