added IndexInfo and more relationship info to neo-persistent-property, extracted class cache for type-strategies
This commit is contained in:
36
pom.xml
36
pom.xml
@@ -236,9 +236,9 @@
|
||||
<plugin>
|
||||
<groupId>com.agilejava.docbkx</groupId>
|
||||
<artifactId>docbkx-maven-plugin</artifactId>
|
||||
<version>2.0.8</version>
|
||||
<version>2.0.12</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<!--execution>
|
||||
<id>single-page</id>
|
||||
<goals>
|
||||
<goal>generate-html</goal>
|
||||
@@ -273,8 +273,31 @@
|
||||
</postProcess>
|
||||
</configuration>
|
||||
<phase>pre-site</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
</execution-->
|
||||
<execution>
|
||||
<id>generate-rtf</id>
|
||||
<goals>
|
||||
<goal>generate-rtf</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<imgSrcPath>${basedir}/src/docbkx/</imgSrcPath>
|
||||
<admonGraphicsPath>${basedir}/src/docbkx/resources/images/</admonGraphicsPath>
|
||||
<sourceDirectory>${basedir}/src/docbkx/</sourceDirectory>
|
||||
<!--foCustomization>${basedir}/src/docbkx/resources/xsl/fortf2.xsl</foCustomization-->
|
||||
<fopExtensions>0</fopExtensions>
|
||||
<fop1Extensions>0</fop1Extensions>
|
||||
<useExtensions>0</useExtensions>
|
||||
<!--highlightSource>1</highlightSource>
|
||||
<highlightDefaultLanguage></highlightDefaultLanguage-->
|
||||
<postProcess>
|
||||
<copy file="${basedir}/target/docbkx/rtf/index.rtf"
|
||||
tofile="${basedir}/target/site/reference/rtf/spring-data-graph-reference.rtf"
|
||||
failonerror="false"/>
|
||||
</postProcess>
|
||||
</configuration>
|
||||
<phase>pre-site</phase>
|
||||
</execution>
|
||||
<!--execution>
|
||||
<id>single-pdf</id>
|
||||
<goals>
|
||||
<goal>generate-pdf</goal>
|
||||
@@ -282,6 +305,7 @@
|
||||
<configuration>
|
||||
<imgSrcPath>${basedir}/src/docbkx/</imgSrcPath>
|
||||
<admonGraphicsPath>${basedir}/src/docbkx/resources/images/</admonGraphicsPath>
|
||||
<foCustomization>${basedir}/src/docbkx/resources/xsl/fopdf.xsl</foCustomization>
|
||||
<useExtensions>1</useExtensions>
|
||||
<highlightSource>1</highlightSource>
|
||||
<highlightDefaultLanguage></highlightDefaultLanguage>
|
||||
@@ -331,7 +355,7 @@
|
||||
</postProcess>
|
||||
</configuration>
|
||||
<phase>pre-site</phase>
|
||||
</execution>
|
||||
</execution-->
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -352,7 +376,7 @@
|
||||
<draftWatermarkImage/>
|
||||
<htmlStylesheet>css/html.css</htmlStylesheet>
|
||||
<sourceDirectory>${basedir}/src/docbkx/</sourceDirectory>
|
||||
<foCustomization>${basedir}/src/docbkx/resources/xsl/fopdf.xsl</foCustomization>
|
||||
<!--foCustomization>${basedir}/src/docbkx/resources/xsl/fopdf.xsl</foCustomization-->
|
||||
<xincludeSupported>true</xincludeSupported>
|
||||
<entities>
|
||||
<entity>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
<junit.version>4.8.1</junit.version>
|
||||
<log4j.version>1.2.15</log4j.version>
|
||||
<org.mockito.version>1.8.4</org.mockito.version>
|
||||
<org.slf4j.version>1.5.10</org.slf4j.version>
|
||||
<org.slf4j.version>1.6.1</org.slf4j.version>
|
||||
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
|
||||
<data.commons.version>1.1.0.RELEASE</data.commons.version>
|
||||
<neo4j.version>1.4.1</neo4j.version>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.data.neo4j.annotation;
|
||||
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.neo4j.core.Direction;
|
||||
import org.springframework.data.neo4j.core.NodeBacked;
|
||||
|
||||
@@ -44,6 +45,7 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Reference
|
||||
public @interface RelatedTo {
|
||||
/**
|
||||
* @return name of the relationship type, optional, can be inferred from the field name
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.Reference;
|
||||
import org.springframework.data.neo4j.core.Direction;
|
||||
import org.springframework.data.neo4j.core.RelationshipBacked;
|
||||
|
||||
@@ -38,6 +39,7 @@ import org.springframework.data.neo4j.core.RelationshipBacked;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Reference
|
||||
public @interface RelatedToVia {
|
||||
/**
|
||||
* @return name of the relationship type, optional, can be inferred from the field name
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.neo4j.helpers.collection.ClosableIterable;
|
||||
* Contains a callback on entity creation that can setup the type representation. The finder methods are delegated to
|
||||
* for the appropriate calls for the strategy set for the datastore.
|
||||
*
|
||||
* TODO use SDC TypeMapper implementations to delegate to for concrete implementation
|
||||
*
|
||||
* @author Michael Hunger
|
||||
* @since 13.09.2010
|
||||
*/
|
||||
|
||||
@@ -33,17 +33,17 @@ public class IndexingPropertyFieldAccessorListenerFactory<S extends PropertyCont
|
||||
|
||||
private final PropertyFieldAccessorFactory propertyFieldAccessorFactory;
|
||||
private final ConvertingNodePropertyFieldAccessorFactory convertingNodePropertyFieldAccessorFactory;
|
||||
private final IndexInfo indexInfo;
|
||||
private final IndexProvider indexProvider;
|
||||
|
||||
public IndexingPropertyFieldAccessorListenerFactory(final GraphDatabaseContext graphDatabaseContext, final PropertyFieldAccessorFactory propertyFieldAccessorFactory, final ConvertingNodePropertyFieldAccessorFactory convertingNodePropertyFieldAccessorFactory) {
|
||||
indexInfo = new IndexInfo<S,T>(graphDatabaseContext);
|
||||
indexProvider = new IndexProvider<S,T>(graphDatabaseContext);
|
||||
this.propertyFieldAccessorFactory = propertyFieldAccessorFactory;
|
||||
this.convertingNodePropertyFieldAccessorFactory = convertingNodePropertyFieldAccessorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(final Field f) {
|
||||
return isPropertyField(f) && indexInfo.isIndexed(f);
|
||||
return isPropertyField(f) && indexProvider.isIndexed(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,14 +53,14 @@ public class IndexingPropertyFieldAccessorListenerFactory<S extends PropertyCont
|
||||
|
||||
@Override
|
||||
public FieldAccessListener<T, ?> forField(Field field) {
|
||||
return (FieldAccessListener<T, ?>) new IndexingPropertyFieldAccessorListener(field,indexInfo);
|
||||
return (FieldAccessListener<T, ?>) new IndexingPropertyFieldAccessorListener(field, indexProvider);
|
||||
}
|
||||
|
||||
|
||||
public static class IndexInfo<S extends PropertyContainer, T extends GraphBacked<S>> {
|
||||
public static class IndexProvider<S extends PropertyContainer, T extends GraphBacked<S>> {
|
||||
private final GraphDatabaseContext graphDatabaseContext;
|
||||
|
||||
public IndexInfo(GraphDatabaseContext graphDatabaseContext) {
|
||||
public IndexProvider(GraphDatabaseContext graphDatabaseContext) {
|
||||
this.graphDatabaseContext = graphDatabaseContext;
|
||||
}
|
||||
|
||||
@@ -108,20 +108,17 @@ public class IndexingPropertyFieldAccessorListenerFactory<S extends PropertyCont
|
||||
|
||||
protected final String indexKey;
|
||||
private final Field field;
|
||||
private final IndexInfo indexInfo;
|
||||
private Index<T> index;
|
||||
private final IndexProvider indexProvider;
|
||||
|
||||
public IndexingPropertyFieldAccessorListener(final Field field, IndexInfo indexInfo) {
|
||||
public IndexingPropertyFieldAccessorListener(final Field field, IndexProvider indexProvider) {
|
||||
this.field = field;
|
||||
this.indexInfo = indexInfo;
|
||||
indexKey = indexInfo.getIndexKey(field);
|
||||
this.indexProvider = indexProvider;
|
||||
indexKey = indexProvider.getIndexKey(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(GraphBacked<T> graphBacked, Object oldVal, Object newVal) {
|
||||
if (index==null) {
|
||||
index = indexInfo.getIndex(field, graphBacked);
|
||||
}
|
||||
Index<T> index = indexProvider.getIndex(field, graphBacked);
|
||||
if (newVal instanceof Number) newVal = ValueContext.numeric((Number) newVal);
|
||||
|
||||
final T state = graphBacked.getPersistentState();
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import org.springframework.data.neo4j.annotation.RelatedTo;
|
||||
import org.springframework.data.neo4j.core.Direction;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link RelationshipInfo} implementation gathering data from a {@link RelatedTo} annotation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class AnnotationBasedRelationshipInfo implements RelationshipInfo {
|
||||
|
||||
private final RelatedTo annotation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationBasedRelationshipInfo} from the given {@link RelatedTo} annotation.
|
||||
*
|
||||
* @param annotation must not be {@literal null}.
|
||||
*/
|
||||
public AnnotationBasedRelationshipInfo(RelatedTo annotation) {
|
||||
Assert.notNull(annotation);
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.neo4j.mapping.RelationshipInfo#getDirection()
|
||||
*/
|
||||
@Override
|
||||
public Direction getDirection() {
|
||||
return annotation.direction();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.neo4j.mapping.RelationshipInfo#getType()
|
||||
*/
|
||||
@Override
|
||||
public String getType() {
|
||||
return annotation.type();
|
||||
}
|
||||
}
|
||||
@@ -41,4 +41,8 @@ public interface Neo4JPersistentProperty extends PersistentProperty<Neo4JPersist
|
||||
* @return
|
||||
*/
|
||||
RelationshipInfo getRelationshipInfo();
|
||||
|
||||
boolean isIndexed();
|
||||
|
||||
Neo4JPersistentPropertyImpl.IndexInfo getIndexInfo();
|
||||
}
|
||||
|
||||
@@ -16,78 +16,131 @@
|
||||
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.RelatedTo;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.AbstractPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.neo4j.annotation.*;
|
||||
import org.springframework.data.neo4j.core.Direction;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Neo4JPersistentProperty}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class Neo4JPersistentPropertyImpl extends AbstractPersistentProperty<Neo4JPersistentProperty> implements
|
||||
Neo4JPersistentProperty {
|
||||
Neo4JPersistentProperty {
|
||||
|
||||
private final RelationshipInfo relationshipInfo;
|
||||
private final boolean isIdProperty;
|
||||
private IndexInfo indexInfo;
|
||||
private Map<Class<? extends Annotation>, ? extends Annotation> annotations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Neo4JPersistentPropertyImpl} from the given {@link Field}, {@link PropertyDescriptor} owner
|
||||
* {@link PersistentEntity} and {@link SimpleTypeHolder}.
|
||||
*
|
||||
* @param field
|
||||
* @param propertyDescriptor
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
*/
|
||||
public Neo4JPersistentPropertyImpl(Field field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, Neo4JPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
PersistentEntity<?, Neo4JPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
|
||||
this.relationshipInfo = field.isAnnotationPresent(RelatedTo.class) ? new AnnotationBasedRelationshipInfo(
|
||||
field.getAnnotation(RelatedTo.class)) : null;
|
||||
this.isIdProperty = field.isAnnotationPresent(GraphId.class);
|
||||
this.annotations = extractAnnotations(field);
|
||||
this.relationshipInfo = extractRelationshipInfo(field);
|
||||
this.indexInfo = extractIndexInfo(field);
|
||||
this.isIdProperty = annotations.containsKey(GraphId.class);
|
||||
}
|
||||
|
||||
private Map<Class<? extends Annotation>,? extends Annotation> extractAnnotations(Field field) {
|
||||
Map<Class<? extends Annotation>, Annotation> result=new IdentityHashMap<Class<? extends Annotation>, Annotation>();
|
||||
for (Annotation annotation : field.getAnnotations()) {
|
||||
result.put(annotation.annotationType(), annotation);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private IndexInfo extractIndexInfo(Field field) {
|
||||
final Indexed annotation = getAnnotation(Indexed.class);
|
||||
return annotation!=null ? new IndexInfo(annotation) : null;
|
||||
}
|
||||
|
||||
private <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
return (T) annotations.get(annotationType);
|
||||
}
|
||||
|
||||
private RelationshipInfo extractRelationshipInfo(final Field field) {
|
||||
if (isAnnotationPresent(RelatedTo.class)) {
|
||||
return RelationshipInfo.fromField(field, getAnnotation(RelatedTo.class), getTypeInformation());
|
||||
}
|
||||
|
||||
if (isAnnotationPresent(RelatedToVia.class)) {
|
||||
return RelationshipInfo.fromField(field, getAnnotation(RelatedToVia.class), getTypeInformation());
|
||||
}
|
||||
if (hasAnnotation(getTypeInformation(), NodeEntity.class)) {
|
||||
return RelationshipInfo.fromField(field, getTypeInformation());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
|
||||
return annotations.containsKey(annotationType);
|
||||
}
|
||||
|
||||
private static boolean hasAnnotation(TypeInformation<?> typeInformation, final Class<NodeEntity> annotationClass) {
|
||||
return typeInformation.getActualType().getClass().isAnnotationPresent(annotationClass);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.PersistentProperty#isIdProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
return this.isIdProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
|
||||
*/
|
||||
@Override
|
||||
protected Association<Neo4JPersistentProperty> createAssociation() {
|
||||
return new Association<Neo4JPersistentProperty>(this, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.neo4j.mapping.Neo4JPersistentProperty#isRelationship()
|
||||
*/
|
||||
@Override
|
||||
public boolean isRelationship() {
|
||||
return this.relationshipInfo != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.neo4j.mapping.Neo4JPersistentProperty#getRelationShipInfo()
|
||||
*/
|
||||
@Override
|
||||
public RelationshipInfo getRelationshipInfo() {
|
||||
return relationshipInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndexed() {
|
||||
return indexInfo != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexInfo getIndexInfo() {
|
||||
return indexInfo;
|
||||
}
|
||||
|
||||
public static class IndexInfo {
|
||||
private String indexName;
|
||||
private boolean fulltext;
|
||||
private final String fieldName;
|
||||
private final Indexed.Level level;
|
||||
|
||||
public IndexInfo(Indexed annotation) {
|
||||
this.indexName = annotation.indexName();
|
||||
this.fulltext = annotation.fulltext();
|
||||
fieldName = annotation.fieldName();
|
||||
level = annotation.level();
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
public boolean isFulltext() {
|
||||
return fulltext;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,26 +16,63 @@
|
||||
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelatedTo;
|
||||
import org.springframework.data.neo4j.annotation.RelatedToVia;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.neo4j.core.Direction;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import scala.annotation.target.field;
|
||||
|
||||
/**
|
||||
* Captures information about a relationship.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface RelationshipInfo {
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Returns the direction of the relationship.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Direction getDirection();
|
||||
public class RelationshipInfo {
|
||||
|
||||
/**
|
||||
* Returns the type of the relationship.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getType();
|
||||
private boolean isMultiple;
|
||||
private final Direction direction;
|
||||
private final String type;
|
||||
private final TypeInformation<?> targetType;
|
||||
private final boolean isNodeRelationship;
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public boolean isMultiple() {
|
||||
return isMultiple;
|
||||
}
|
||||
|
||||
public RelationshipInfo(String type, Direction direction, TypeInformation<?> typeInformation) {
|
||||
this.type = type;
|
||||
this.direction = direction;
|
||||
isMultiple = typeInformation.isCollectionLike();
|
||||
targetType = typeInformation.getActualType();
|
||||
isNodeRelationship = isNodeEntity(targetType);
|
||||
}
|
||||
|
||||
private boolean isNodeEntity(TypeInformation<?> targetType) {
|
||||
if (targetType.getType().isAnnotationPresent(NodeEntity.class)) return true;
|
||||
if (targetType.getType().isAnnotationPresent(RelationshipEntity.class)) return false;
|
||||
throw new MappingException("Target type for relationship "+ type +" field is invalid "+targetType);
|
||||
}
|
||||
|
||||
public static RelationshipInfo fromField(Field field, TypeInformation<?> typeInformation) {
|
||||
return new RelationshipInfo(field.getName(), Direction.OUTGOING, typeInformation);
|
||||
}
|
||||
public static RelationshipInfo fromField(Field field, RelatedTo annotation, TypeInformation<?> typeInformation) {
|
||||
return new RelationshipInfo(
|
||||
annotation.type().isEmpty() ? field.getName() : annotation.type(),
|
||||
annotation.direction(),
|
||||
typeInformation);
|
||||
}
|
||||
public static RelationshipInfo fromField(Field field, RelatedToVia annotation, TypeInformation<?> typeInformation) {
|
||||
return new RelationshipInfo(
|
||||
annotation.type().isEmpty() ? field.getName() : annotation.type(),
|
||||
annotation.direction(),
|
||||
typeInformation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +78,11 @@ public class GraphRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata, GraphDatabaseContext graphDatabaseContext) {
|
||||
|
||||
Class<?> repositoryInterface = metadata.getRepositoryInterface();
|
||||
Class<?> type = metadata.getDomainClass();
|
||||
GraphEntityInformation entityInformation = (GraphEntityInformation)getEntityInformation(type);
|
||||
|
||||
// todo entityInformation.isGraphBacked();
|
||||
if (entityInformation.isNodeEntity()) {
|
||||
return new NodeGraphRepository(type,graphDatabaseContext);
|
||||
} else {
|
||||
|
||||
@@ -37,7 +37,7 @@ public class GenericTypeExtractor {
|
||||
}
|
||||
|
||||
public static Class<?> resolveConcreteType(Class<?> type, final Type genericType) {
|
||||
if (Iterable.class.isAssignableFrom(type) || Page.class.isAssignableFrom(type)) {
|
||||
if (Iterable.class.isAssignableFrom(type)) {
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
ParameterizedType returnType = (ParameterizedType) genericType;
|
||||
Type componentType = returnType.getActualTypeArguments()[0];
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.support.typerepresentation;
|
||||
|
||||
import org.neo4j.graphdb.NotFoundException;
|
||||
import org.springframework.data.neo4j.core.GraphBacked;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 22.09.11
|
||||
*/
|
||||
class EntityTypeCache {
|
||||
private final Map<String, Class<?>> cache = new WeakHashMap<String, Class<?>>();
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
<ENTITY extends GraphBacked<?>> Class<ENTITY> getClassForName(String className) {
|
||||
try {
|
||||
Class<ENTITY> result = (Class<ENTITY>) cache.get(className);
|
||||
if (result != null) return result;
|
||||
synchronized (cache) {
|
||||
result = (Class<ENTITY>) cache.get(className);
|
||||
if (result != null) return result;
|
||||
result = (Class<ENTITY>) Class.forName(className);
|
||||
cache.put(className, result);
|
||||
return result;
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
return null;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.persistence.EntityInstantiator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresentationStrategy {
|
||||
|
||||
@@ -39,12 +40,13 @@ public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresent
|
||||
public static final String INDEX_KEY = "className";
|
||||
private EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
private GraphDatabaseService graphDb;
|
||||
private final Map<String,Class<?>> cache=new HashMap<String, Class<?>>();
|
||||
private final EntityTypeCache typeCache;
|
||||
|
||||
public IndexingNodeTypeRepresentationStrategy(GraphDatabaseService graphDb,
|
||||
EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
|
||||
this.graphDb = graphDb;
|
||||
this.graphEntityInstantiator = graphEntityInstantiator;
|
||||
typeCache = new EntityTypeCache();
|
||||
}
|
||||
|
||||
private Index<Node> getNodeTypesIndex() {
|
||||
@@ -92,26 +94,7 @@ public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresent
|
||||
public Class<? extends NodeBacked> getJavaType(Node node) {
|
||||
if (node == null) throw new IllegalArgumentException("Node is null");
|
||||
String className = (String) node.getProperty(TYPE_PROPERTY_NAME);
|
||||
return getClassForName(className);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private <ENTITY extends GraphBacked<?>> Class<ENTITY> getClassForName(String className) {
|
||||
try {
|
||||
Class<ENTITY> result= (Class<ENTITY>) cache.get(className);
|
||||
if (result!=null) return result;
|
||||
synchronized (cache) {
|
||||
result= (Class<ENTITY>) cache.get(className);
|
||||
if (result!=null) return result;
|
||||
result = (Class<ENTITY>) Class.forName(className);
|
||||
cache.put(className,result);
|
||||
return result;
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
return null;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
return typeCache.getClassForName(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,7 +33,9 @@ import org.springframework.data.neo4j.core.RelationshipTypeRepresentationStrateg
|
||||
import org.springframework.data.persistence.EntityInstantiator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class IndexingRelationshipTypeRepresentationStrategy implements RelationshipTypeRepresentationStrategy {
|
||||
|
||||
@@ -42,18 +44,15 @@ public class IndexingRelationshipTypeRepresentationStrategy implements Relations
|
||||
public static final String INDEX_KEY = "className";
|
||||
private EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator;
|
||||
private GraphDatabaseService graphDb;
|
||||
private final Map<String,Class<?>> cache=new HashMap<String, Class<?>>();
|
||||
private final EntityTypeCache typeCache;
|
||||
|
||||
public IndexingRelationshipTypeRepresentationStrategy(GraphDatabaseService graphDb,
|
||||
EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator) {
|
||||
this.graphDb = graphDb;
|
||||
this.relationshipEntityInstantiator = relationshipEntityInstantiator;
|
||||
typeCache = new EntityTypeCache();
|
||||
}
|
||||
|
||||
private Index<Node> getNodeTypesIndex() {
|
||||
return graphDb.index().forNodes(INDEX_NAME);
|
||||
}
|
||||
|
||||
private Index<Relationship> getRelTypesIndex() {
|
||||
return graphDb.index().forRelationships(INDEX_NAME);
|
||||
}
|
||||
@@ -87,8 +86,10 @@ public class IndexingRelationshipTypeRepresentationStrategy implements Relations
|
||||
@Override
|
||||
public long count(Class<? extends RelationshipBacked> entityClass) {
|
||||
long count = 0;
|
||||
for (Object o : getRelTypesIndex().get(INDEX_KEY, entityClass.getName())) {
|
||||
count += 1;
|
||||
final IndexHits<Relationship> hits = getRelTypesIndex().get(INDEX_KEY, entityClass.getName());
|
||||
while (hits.hasNext()) {
|
||||
hits.next();
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -96,28 +97,9 @@ public class IndexingRelationshipTypeRepresentationStrategy implements Relations
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<? extends RelationshipBacked> getJavaType(Relationship relationship) {
|
||||
if (relationship == null) throw new IllegalArgumentException("Node is null");
|
||||
if (relationship == null) throw new IllegalArgumentException("Relationship is null");
|
||||
String className = (String) relationship.getProperty(TYPE_PROPERTY_NAME);
|
||||
return getClassForName(className);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private <ENTITY extends GraphBacked<?>> Class<ENTITY> getClassForName(String className) {
|
||||
try {
|
||||
Class<ENTITY> result= (Class<ENTITY>) cache.get(className);
|
||||
if (result!=null) return result;
|
||||
synchronized (cache) {
|
||||
result= (Class<ENTITY>) cache.get(className);
|
||||
if (result!=null) return result;
|
||||
result = (Class<ENTITY>) Class.forName(className);
|
||||
cache.put(className,result);
|
||||
return result;
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
return null;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
return typeCache.getClassForName(className);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.neo4j.helpers.collection.ClosableIterable;
|
||||
import org.neo4j.helpers.collection.CombiningIterable;
|
||||
import org.neo4j.helpers.collection.IterableWrapper;
|
||||
import org.neo4j.kernel.Traversal;
|
||||
import org.springframework.data.neo4j.core.GraphBacked;
|
||||
import org.springframework.data.neo4j.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.core.NodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.persistence.EntityInstantiator;
|
||||
@@ -54,11 +55,13 @@ public class SubReferenceNodeTypeRepresentationStrategy implements NodeTypeRepre
|
||||
|
||||
private GraphDatabaseService graphDatabaseService;
|
||||
private EntityInstantiator<NodeBacked, Node> entityInstantiator;
|
||||
private final EntityTypeCache typeCache;
|
||||
|
||||
public SubReferenceNodeTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> entityInstantiator) {
|
||||
public SubReferenceNodeTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> entityInstantiator) {
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
this.entityInstantiator = entityInstantiator;
|
||||
}
|
||||
typeCache = new EntityTypeCache();
|
||||
}
|
||||
|
||||
public static Node getSingleOtherNode(Node node, RelationshipType type,
|
||||
Direction direction) {
|
||||
@@ -125,18 +128,24 @@ public class SubReferenceNodeTypeRepresentationStrategy implements NodeTypeRepre
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends NodeBacked> Class<T> getJavaType(Node node) {
|
||||
if (node==null) throw new IllegalArgumentException("Node is null");
|
||||
if (node == null) throw new IllegalArgumentException("Node is null");
|
||||
Relationship instanceOfRelationship = node.getSingleRelationship(INSTANCE_OF_RELATIONSHIP_TYPE, Direction.OUTGOING);
|
||||
if (instanceOfRelationship==null) throw new IllegalArgumentException("The node "+node+" is not attached to a type hierarchy.");
|
||||
if (instanceOfRelationship == null)
|
||||
throw new IllegalArgumentException("The node " + node + " is not attached to a type hierarchy.");
|
||||
Node subrefNode = instanceOfRelationship.getEndNode();
|
||||
try {
|
||||
Class<T> clazz = (Class<T>) Class.forName((String) subrefNode.getProperty(SUBREF_CLASS_KEY)).asSubclass(NodeBacked.class);
|
||||
if (log.isDebugEnabled()) log.debug("Found class " + clazz.getSimpleName() + " for node: " + node);
|
||||
return clazz;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Unable to get type for node: " + node, e);
|
||||
}
|
||||
}
|
||||
final String typeName = (String) subrefNode.getProperty(SUBREF_CLASS_KEY);
|
||||
Class<T> clazz = resolveType(node, typeName);
|
||||
if (log.isDebugEnabled()) log.debug("Found class " + clazz.getSimpleName() + " for node: " + node);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
private <T extends NodeBacked> Class<T> resolveType(Node node, String typeName) {
|
||||
final Class<GraphBacked<?>> type = typeCache.getClassForName(typeName);
|
||||
if (type == null) {
|
||||
throw new IllegalStateException("Unable to get type for node: " + node);
|
||||
}
|
||||
return (Class<T>) type.asSubclass(NodeBacked.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preEntityRemoval(Node state) {
|
||||
|
||||
@@ -19,5 +19,5 @@ package org.springframework.data.neo4j;
|
||||
import org.springframework.data.neo4j.annotation.*;
|
||||
|
||||
@NodeEntity
|
||||
public class SubGroup extends Group {
|
||||
public class SubGroup extends Group {
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.neo4j.Person;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 19.09.11
|
||||
*/
|
||||
public class Neo4JMappingContextTest {
|
||||
|
||||
private Neo4JMappingContext mappingContext;
|
||||
private Neo4JPersistentEntityImpl<?> personType;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mappingContext = new Neo4JMappingContext();
|
||||
personType = mappingContext.getPersistentEntity(Person.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkGraphIdProperty() {
|
||||
final Neo4JPersistentProperty idProperty = personType.getIdProperty();
|
||||
assertEquals("graphId", idProperty.getName());
|
||||
}
|
||||
|
||||
@Test public void checkNameProperty() {
|
||||
final Neo4JPersistentProperty nameProperty = personType.getPersistentProperty("name");
|
||||
assertEquals("name",nameProperty.getName());
|
||||
assertEquals(String.class,nameProperty.getType());
|
||||
assertEquals(true,nameProperty.isIndexed());
|
||||
assertEquals(Person.NAME_INDEX,nameProperty.getIndexInfo().getIndexName());
|
||||
assertEquals(false,nameProperty.getIndexInfo().isFulltext());
|
||||
assertEquals(false,nameProperty.isRelationship());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user