From 73cf0ce8d509448dc01c948d2dada3a2f36a331e Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Fri, 23 Sep 2011 01:51:36 +0200 Subject: [PATCH] added IndexInfo and more relationship info to neo-persistent-property, extracted class cache for type-strategies --- pom.xml | 36 ++++- spring-data-graph-parent/pom.xml | 2 +- .../data/neo4j/annotation/RelatedTo.java | 2 + .../data/neo4j/annotation/RelatedToVia.java | 2 + .../core/TypeRepresentationStrategy.java | 2 + ...gPropertyFieldAccessorListenerFactory.java | 25 ++-- .../AnnotationBasedRelationshipInfo.java | 59 -------- .../mapping/Neo4JPersistentProperty.java | 4 + .../mapping/Neo4JPersistentPropertyImpl.java | 127 +++++++++++++----- .../data/neo4j/mapping/RelationshipInfo.java | 73 +++++++--- .../repository/GraphRepositoryFactory.java | 3 +- .../neo4j/support/GenericTypeExtractor.java | 2 +- .../typerepresentation/EntityTypeCache.java | 49 +++++++ ...ndexingNodeTypeRepresentationStrategy.java | 25 +--- ...elationshipTypeRepresentationStrategy.java | 38 ++---- ...ferenceNodeTypeRepresentationStrategy.java | 33 +++-- .../springframework/data/neo4j/SubGroup.java | 2 +- .../mapping/Neo4JMappingContextTest.java | 56 ++++++++ 18 files changed, 341 insertions(+), 199 deletions(-) delete mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/AnnotationBasedRelationshipInfo.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/EntityTypeCache.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4JMappingContextTest.java diff --git a/pom.xml b/pom.xml index f10480c2e..db5109bb9 100644 --- a/pom.xml +++ b/pom.xml @@ -236,9 +236,9 @@ com.agilejava.docbkx docbkx-maven-plugin - 2.0.8 + 2.0.12 - + + + generate-rtf + + generate-rtf + + + ${basedir}/src/docbkx/ + ${basedir}/src/docbkx/resources/images/ + ${basedir}/src/docbkx/ + + 0 + 0 + 0 + + + + + + pre-site + + @@ -352,7 +376,7 @@ css/html.css ${basedir}/src/docbkx/ - ${basedir}/src/docbkx/resources/xsl/fopdf.xsl + true diff --git a/spring-data-graph-parent/pom.xml b/spring-data-graph-parent/pom.xml index fe17df9d7..54874efb1 100644 --- a/spring-data-graph-parent/pom.xml +++ b/spring-data-graph-parent/pom.xml @@ -122,7 +122,7 @@ 4.8.1 1.2.15 1.8.4 - 1.5.10 + 1.6.1 3.0.5.RELEASE 1.1.0.RELEASE 1.4.1 diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedTo.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedTo.java index 4f044ace8..80f77258f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedTo.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedTo.java @@ -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 diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedToVia.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedToVia.java index 93b4eec86..e95b0cd56 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedToVia.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/annotation/RelatedToVia.java @@ -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 diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/TypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/TypeRepresentationStrategy.java index 93939ead1..65c4aa5ba 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/TypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/TypeRepresentationStrategy.java @@ -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 */ diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java index 74cd52bd8..5a215953a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java @@ -33,17 +33,17 @@ public class IndexingPropertyFieldAccessorListenerFactory(graphDatabaseContext); + indexProvider = new IndexProvider(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 forField(Field field) { - return (FieldAccessListener) new IndexingPropertyFieldAccessorListener(field,indexInfo); + return (FieldAccessListener) new IndexingPropertyFieldAccessorListener(field, indexProvider); } - public static class IndexInfo> { + public static class IndexProvider> { private final GraphDatabaseContext graphDatabaseContext; - public IndexInfo(GraphDatabaseContext graphDatabaseContext) { + public IndexProvider(GraphDatabaseContext graphDatabaseContext) { this.graphDatabaseContext = graphDatabaseContext; } @@ -108,20 +108,17 @@ public class IndexingPropertyFieldAccessorListenerFactory 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 graphBacked, Object oldVal, Object newVal) { - if (index==null) { - index = indexInfo.getIndex(field, graphBacked); - } + Index index = indexProvider.getIndex(field, graphBacked); if (newVal instanceof Number) newVal = ValueContext.numeric((Number) newVal); final T state = graphBacked.getPersistentState(); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/AnnotationBasedRelationshipInfo.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/AnnotationBasedRelationshipInfo.java deleted file mode 100644 index baa9eaee2..000000000 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/AnnotationBasedRelationshipInfo.java +++ /dev/null @@ -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(); - } -} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java index 243cbf47a..de6ba6f19 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4JPersistentProperty.java @@ -41,4 +41,8 @@ public interface Neo4JPersistentProperty extends PersistentProperty implements -Neo4JPersistentProperty { + Neo4JPersistentProperty { private final RelationshipInfo relationshipInfo; private final boolean isIdProperty; + private IndexInfo indexInfo; + private Map, ? 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 owner, SimpleTypeHolder simpleTypeHolder) { + PersistentEntity 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,? extends Annotation> extractAnnotations(Field field) { + Map, Annotation> result=new IdentityHashMap, 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 getAnnotation(Class 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 boolean isAnnotationPresent(Class annotationType) { + return annotations.containsKey(annotationType); + } + + private static boolean hasAnnotation(TypeInformation typeInformation, final Class 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 createAssociation() { return new Association(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; + } + } + } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/RelationshipInfo.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/RelationshipInfo.java index 1e5a749ef..f96eec5e3 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/RelationshipInfo.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/RelationshipInfo.java @@ -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); + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java index b150c1713..29b68e1f6 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java @@ -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 { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GenericTypeExtractor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GenericTypeExtractor.java index d1f936642..98d6ad013 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GenericTypeExtractor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GenericTypeExtractor.java @@ -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]; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/EntityTypeCache.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/EntityTypeCache.java new file mode 100644 index 000000000..0b4422224 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/EntityTypeCache.java @@ -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> cache = new WeakHashMap>(); + + @SuppressWarnings({"unchecked"}) + > Class getClassForName(String className) { + try { + Class result = (Class) cache.get(className); + if (result != null) return result; + synchronized (cache) { + result = (Class) cache.get(className); + if (result != null) return result; + result = (Class) Class.forName(className); + cache.put(className, result); + return result; + } + } catch (NotFoundException e) { + return null; + } catch (ClassNotFoundException e) { + return null; + } + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingNodeTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingNodeTypeRepresentationStrategy.java index ddc57ee3f..78bac7bf7 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingNodeTypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingNodeTypeRepresentationStrategy.java @@ -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 graphEntityInstantiator; private GraphDatabaseService graphDb; - private final Map> cache=new HashMap>(); + private final EntityTypeCache typeCache; public IndexingNodeTypeRepresentationStrategy(GraphDatabaseService graphDb, EntityInstantiator graphEntityInstantiator) { this.graphDb = graphDb; this.graphEntityInstantiator = graphEntityInstantiator; + typeCache = new EntityTypeCache(); } private Index getNodeTypesIndex() { @@ -92,26 +94,7 @@ public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresent public Class 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 > Class getClassForName(String className) { - try { - Class result= (Class) cache.get(className); - if (result!=null) return result; - synchronized (cache) { - result= (Class) cache.get(className); - if (result!=null) return result; - result = (Class) Class.forName(className); - cache.put(className,result); - return result; - } - } catch (NotFoundException e) { - return null; - } catch (ClassNotFoundException e) { - return null; - } + return typeCache.getClassForName(className); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategy.java index 81315a028..16f652351 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/IndexingRelationshipTypeRepresentationStrategy.java @@ -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 relationshipEntityInstantiator; private GraphDatabaseService graphDb; - private final Map> cache=new HashMap>(); + private final EntityTypeCache typeCache; public IndexingRelationshipTypeRepresentationStrategy(GraphDatabaseService graphDb, EntityInstantiator relationshipEntityInstantiator) { this.graphDb = graphDb; this.relationshipEntityInstantiator = relationshipEntityInstantiator; + typeCache = new EntityTypeCache(); } - private Index getNodeTypesIndex() { - return graphDb.index().forNodes(INDEX_NAME); - } - private Index getRelTypesIndex() { return graphDb.index().forRelationships(INDEX_NAME); } @@ -87,8 +86,10 @@ public class IndexingRelationshipTypeRepresentationStrategy implements Relations @Override public long count(Class entityClass) { long count = 0; - for (Object o : getRelTypesIndex().get(INDEX_KEY, entityClass.getName())) { - count += 1; + final IndexHits 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 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 > Class getClassForName(String className) { - try { - Class result= (Class) cache.get(className); - if (result!=null) return result; - synchronized (cache) { - result= (Class) cache.get(className); - if (result!=null) return result; - result = (Class) Class.forName(className); - cache.put(className,result); - return result; - } - } catch (NotFoundException e) { - return null; - } catch (ClassNotFoundException e) { - return null; - } + return typeCache.getClassForName(className); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategy.java index c1f0b0fd4..f77d4aa6f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/typerepresentation/SubReferenceNodeTypeRepresentationStrategy.java @@ -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 entityInstantiator; + private final EntityTypeCache typeCache; - public SubReferenceNodeTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator entityInstantiator) { + public SubReferenceNodeTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator 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 Class 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 clazz = (Class) 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 clazz = resolveType(node, typeName); + if (log.isDebugEnabled()) log.debug("Found class " + clazz.getSimpleName() + " for node: " + node); + return clazz; + } + + private Class resolveType(Node node, String typeName) { + final Class> type = typeCache.getClassForName(typeName); + if (type == null) { + throw new IllegalStateException("Unable to get type for node: " + node); + } + return (Class) type.asSubclass(NodeBacked.class); + } @Override public void preEntityRemoval(Node state) { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/SubGroup.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/SubGroup.java index 2f7ac12df..2675382d9 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/SubGroup.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/SubGroup.java @@ -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 { } \ No newline at end of file diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4JMappingContextTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4JMappingContextTest.java new file mode 100644 index 000000000..ea208ceb4 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4JMappingContextTest.java @@ -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()); + } +}