【问题标题】:Spring Annotation Object Mapping generic class relationshipSpring Annotation Object Mapping 泛型类关系
【发布时间】:2021-05-17 08:52:02
【问题描述】:

我使用 Spring 将基于注释的对象映射中的对象存储在 Neo4j 数据库中。

我有一个泛型类 (InformationMutable),它包含作为类属性的另一个具有相同泛型数据类型的类 (InformationEntry) 的列表 - private List<InformationEntry<T>> entries = new ArrayList<>();

Full InformationMutable 类:

package de.skillkiller.project.entity;

import lombok.*;
import org.springframework.data.neo4j.core.schema.Node;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@EqualsAndHashCode(callSuper = true)
@Node
@Data
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class InformationMutable<T extends Serializable> extends Information {
    private List<InformationEntry<T>> entries = new ArrayList<>();

    public void addEntry(T entry) {
        entries.add(new InformationEntry<>(entry));
    }

    public void removeEntry(InformationEntry<T> entry) {
        entries.remove(entry);
    }
}

目标是有一个对象,其中列表中只有另一个类的对象,但其中具有相同的数据类型。 InformationEntry 类使用统一的创建和更新日期扩展数据类型。

其他必修课: 信息输入:

package de.skillkiller.project.entity;

import lombok.*;
import org.springframework.data.neo4j.core.schema.Node;

import java.io.Serializable;

@EqualsAndHashCode(callSuper = true)
@Node
@Data
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class InformationEntry<T extends Serializable> extends BasicNode{
    private T entry;
}

信息:

package de.skillkiller.project.entity;

import lombok.*;
import org.springframework.data.neo4j.core.schema.Node;

@EqualsAndHashCode(callSuper = true)
@Node
@Data
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public abstract class Information extends BasicNode{
    private String information;
}

基本节点:

package de.skillkiller.project.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.support.DateLong;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public abstract class BasicNode {
    @Id
    @GeneratedValue
    private Long id;

    @DateLong
    @LastModifiedDate
    private Date changedAt = new Date();

    @DateLong
    @CreatedDate
    private Date enteredAt = new Date();
}

信息存储库:

package de.skillkiller.project.repository;

import de.skillkiller.project.entity.Information;
import org.springframework.data.neo4j.repository.Neo4jRepository;

public interface InformationRepository extends Neo4jRepository<Information, Long> {
}

创作过程:

InformationMutable<Integer> informationMutable1 = new InformationMutable<>();
informationMutable1.addEntry(5);
informationMutable1.addEntry(15);
informationMutable1.setInformation("Test");
informationRepository.save(informationMutable1);

如果我现在从类 InformationMutable 创建一个对象,将值添加到列表中并想要保存它,我会收到以下错误消息:

ava.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:807) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:788) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.4.2.jar:2.4.2]
    at de.skillkiller.project.ProjectApplication.main(ProjectApplication.java:19) ~[classes/:na]
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.data.neo4j.core.mapping.Neo4jPersistentEntity.isNew(Object)" because "targetNodeDescription" is null
    at org.springframework.data.neo4j.core.Neo4jTemplate.lambda$processNestedRelations$16(Neo4jTemplate.java:495) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:387) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.neo4j.core.Neo4jTemplate.processNestedRelations(Neo4jTemplate.java:452) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.neo4j.core.Neo4jTemplate.lambda$processNestedRelations$16(Neo4jTemplate.java:518) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:387) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.neo4j.core.Neo4jTemplate.processNestedRelations(Neo4jTemplate.java:452) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.neo4j.core.Neo4jTemplate.processRelations(Neo4jTemplate.java:442) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.neo4j.core.Neo4jTemplate.saveImpl(Neo4jTemplate.java:254) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.neo4j.core.Neo4jTemplate.save(Neo4jTemplate.java:225) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at org.springframework.data.neo4j.repository.support.SimpleNeo4jRepository.save(SimpleNeo4jRepository.java:131) ~[spring-data-neo4j-6.0.3.jar:6.0.3]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:524) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:531) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:156) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.4.3.jar:2.4.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.3.jar:5.3.3]
    at com.sun.proxy.$Proxy67.save(Unknown Source) ~[na:na]
    at de.skillkiller.project.ProjectApplication.lambda$demo$0(ProjectApplication.java:57) ~[classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:804) ~[spring-boot-2.4.2.jar:2.4.2]
    ... 5 common frames omitted

尽管如此,Spring 和 Neo4j 是否有可能存储这样一个通用结构并再次读取它?

【问题讨论】:

    标签: spring spring-data spring-data-neo4j


    【解决方案1】:

    您的设置的问题在于 InformationMutable 声明了一个通用字段,SDN 将其视为任何其他合法的 @Node 注释实体。 因此 SDN 想要创建类似的东西

    (:Information:InformationMutable) -[:ENTRIES]-> (:InformationEntry) -[:ENTRY] -> (generic entry)
    

    它不会将泛型字段视为可能的属性,因为Integer 类型的定义是在运行时完成的。 例如,右侧的绿色节点是您可以使用的其他真实 @Node 实体,它们包含固定的 Integer 字段。

    【讨论】:

    • 谢谢,我还注意到在 Java 中我根本无法将类转换为正确的子类。
    猜你喜欢
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多