added IndexInfo and more relationship info to neo-persistent-property, extracted class cache for type-strategies

This commit is contained in:
Michael Hunger
2011-09-23 01:51:36 +02:00
parent 755cb4d36e
commit 73cf0ce8d5
18 changed files with 341 additions and 199 deletions

36
pom.xml
View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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();

View File

@@ -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();
}
}

View File

@@ -41,4 +41,8 @@ public interface Neo4JPersistentProperty extends PersistentProperty<Neo4JPersist
* @return
*/
RelationshipInfo getRelationshipInfo();
boolean isIndexed();
Neo4JPersistentPropertyImpl.IndexInfo getIndexInfo();
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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];

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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 {
}

View File

@@ -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());
}
}