All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.data.neo4j.mapping.Neo4jPersistentProperty Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright 2011-2024 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
 *
 *      https://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 java.lang.reflect.Field;
import java.util.Optional;

import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.StartNode;
import org.neo4j.ogm.annotation.Version;
import org.neo4j.ogm.metadata.ClassInfo;
import org.neo4j.ogm.metadata.FieldInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.neo4j.annotation.QueryResult;

/**
 * This class implements Spring Data's PersistentProperty interface, scavenging the required data from the OGM's mapping
 * classes in order to for SDN to play nicely with Spring Data REST. The main thing to note is that this class is
 * effectively a shim for FieldInfo. We don't reload all the mapping information again. We do not yet support
 * getter/setter access to entity properties.
 * 

* These attributes do not appear to be used/needed for SDN 4 to inter-operate correctly with SD-REST: *

*
    *
  • mapValueType
  • *
  • typeInformation
  • *
  • isVersionProperty (there is no SDN versioning at this stage)
  • *
  • isTransient (we never supply transient classes to the Spring mapping context)
  • *
  • isWritable (we don't currently support read-only fields)
  • *
* Consequently their associated getter methods always return default values of null or [true|false] However, because * these method calls are not expected, we also log a warning message if they get invoked * * @author Vince Bickers * @author Adam George * @author Luanne Misquitta * @author Mark Angrish * @author Mark Paluch * @author Michael J. Simons * @since 4.0.0 */ public class Neo4jPersistentProperty extends AnnotationBasedPersistentProperty { private static final Logger logger = LoggerFactory.getLogger(Neo4jPersistentProperty.class); enum PropertyType { REGULAR_PROPERTY(false), INTERNAL_ID_PROPERTY(true), ID_PROPERTY(true); private final boolean idProperty; PropertyType(boolean idProperty) { this.idProperty = idProperty; } } private final PropertyType propertyType; /** * Constructs a new {@link Neo4jPersistentProperty} based on the given arguments. * * @param owningClassInfo The {@link ClassInfo} of the object of which the property field is a member * @param property The property * @param owner The owning {@link PersistentEntity} that corresponds to the given {@code ClassInfo} * @param simpleTypeHolder The {@link SimpleTypeHolder} that dictates whether the type of this property is considered * simple or not */ public Neo4jPersistentProperty(ClassInfo owningClassInfo, Property property, PersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { super(property, owner, simpleTypeHolder); if (owningClassInfo == null) { logger.warn("Owning ClassInfo is null for property: {}", property); } if (owningClassInfo == null || owningClassIsSimple(owningClassInfo, simpleTypeHolder) || owningClassDoesNotSupportIdProperties(owningClassInfo) || owningPropertyIsEnum(owner)) { this.propertyType = PropertyType.REGULAR_PROPERTY; } else if (isInternalIdentityField(owningClassInfo, property)) { this.propertyType = PropertyType.INTERNAL_ID_PROPERTY; } else if (isExplicitIdentityField(owningClassInfo, property)) { this.propertyType = PropertyType.ID_PROPERTY; } else { this.propertyType = PropertyType.REGULAR_PROPERTY; } } private static boolean owningPropertyIsEnum(PersistentEntity owner) { return owner.getType().isEnum(); } private static boolean owningClassIsSimple(ClassInfo owningClassInfo, SimpleTypeHolder simpleTypeHolder) { return owningClassInfo.getUnderlyingClass() != null && simpleTypeHolder.isSimpleType(owningClassInfo.getUnderlyingClass()); } private static boolean owningClassDoesNotSupportIdProperties(ClassInfo owningClassInfo) { return owningClassInfo.isInterface() || owningClassInfo.annotationsInfo().get(QueryResult.class.getName()) != null || owningClassInfo.isEnum(); } private static boolean isInternalIdentityField(ClassInfo owningClassInfo, Property property) { Optional optionalInternalIdentityField = Optional.ofNullable(owningClassInfo.identityFieldOrNull()) .map(FieldInfo::getField); return property.getField().equals(optionalInternalIdentityField); } private static boolean isExplicitIdentityField(ClassInfo owningClassInfo, Property property) { // Cannot use owningClassInfo.propertyField() as those are not initialized yet. They will // be initialized on the call, but that would change behaviour: SDN fails late when there // are invalid properties atm. Even if'ts better to fail early, it means at least changing // a dozen tests in SDN itself. return property.getField().map(field -> AnnotatedElementUtils.findMergedAnnotation(field, Id.class)).isPresent(); } @Override public boolean isIdProperty() { return propertyType.idProperty; } /** * @return True if this property describes the internal ID property. */ public boolean isInternalIdProperty() { return propertyType == PropertyType.INTERNAL_ID_PROPERTY; } PropertyType getPropertyType() { return propertyType; } @Override public boolean isVersionProperty() { return isAnnotationPresent(Version.class); } /** * Overridden to force field access as opposed to getter method access for simplicity. * * @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#usePropertyAccess() */ @Override public boolean usePropertyAccess() { logger.debug("[property].usePropertyAccess() returns false"); return false; } /** * Determines whether or not this property should be considered an association to another entity or whether it's just * a simple property that should be shown as a value. *

* This implementation works by looking for non-transient members annotated with @Relationship. *

* * @return true if this property is an association to another entity, false if not */ @Override public boolean isAssociation() { return !isTransient() && (isAnnotationPresent(Relationship.class) || isAnnotationPresent(StartNode.class) || isAnnotationPresent(EndNode.class)); } @Override protected Association createAssociation() { return new Association<>(this, null); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy