Home > database >  JPA entity is null in service layer
JPA entity is null in service layer

Time:03-09

So I have this problem where my the parameter i pass into my service layer function is always null no matter what. the error i get is Caused by: java.lang.IllegalArgumentException: The given id must not be null! which happens exactly in the node.get(id) in service layer because the node is null.

this is how my app looks like :

Node class

@Entity
@Data
public class Node {
    @Id
    @GeneratedValue(strategy = IDENTITY)

    private Long id;

    private int depth;

    private double value;

    @Column(unique=true)
    private String name;

    @ManyToOne //add column definitions as needed
    @JoinColumn(name="parent_id")
    private Node parent;      //each Domain with parent==null is a root domain, all others are subdomains


    @OneToMany(mappedBy = "parent",cascade = {CascadeType.REMOVE,CascadeType.PERSIST}) //add column definitions as needed
    private List<Node> children;

    public Node(final Node parent) {
        if(parent==null) throw new IllegalArgumentException("parent required");

        this.parent = parent;
        this.children = new ArrayList<>();
        if (parent==null) {
            this.depth=0;
        }
        else {
            this.depth = (parent.getDepth()   1);
        }
        registerInParentsChilds();
    }
    public Node() {
        this.children = new ArrayList<>();
        if (parent==null) {
            this.depth=0;
        }
        else {
            this.depth = (parent.getDepth()   1);
        }
    }
    /** Register this domain in the child list of its parent. */
    private void registerInParentsChilds() {

        this.parent.children.add(this);
    }

    public List<Node> getChildren() {
        return this.children;
    }
    public void move(final Node newParent)  {
        try {

            this.parent.children.remove(this);
            this.parent = newParent;
            registerInParentsChilds();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
    public static Node createRoot() {
        return new Node();
    }


}

NodeRepostiory :

public interface NodeRepository extends JpaRepository<Node, Long> {
    Optional<Node> findById(Long id);

}

NodeService:

public interface NodeService {
    Node saveNode(Node node);

}

NodeServiceImpl:

@Service @RequiredArgsConstructor @Transactional @Slf4j
public class NodeServiceImpl implements NodeService{

    @Autowired
    private  NodeRepository nodeRepository;

    @Override
    public Node saveNode(Node node) {
        log.info("saving new node {} to DB", node);
        Optional<Node> existing_node = nodeRepository.findById(node.getId());
        if (existing_node.get()!=null) {
            log.info("node already exists");
            return null;

        } else {
            log.info("node saved");
            return nodeRepository.save(node);
        }
    }
}

MainApp

@Bean
    CommandLineRunner run_again(NodeService nodeService) { //this runs after the app is initialized, so no need for
        //manual input
        return args -> {

            Node root;
            root = Node.createRoot();
            nodeService.saveNode(root);
            System.out.println("root created");

            nodeService.saveNode(new Node(root));
            System.out.println("a created");

            Node b = new Node(root);
            nodeService.saveNode(b);

            System.out.println("b created");
            Node c = new Node();
            nodeService.saveNode(c);

            System.out.println("c created");


        };
    }

this is my error stack ( like i said i know exactly where the problem is coming from but i can't fix it ) :

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:772) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:753) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:309) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.6.3.jar:2.6.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.6.3.jar:2.6.3]
    at com.example.app.AppApplication.main(AppApplication.java:38) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.6.3.jar:2.6.3]
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: The given id must not be null!; nested exception is java.lang.IllegalArgumentException: The given id must not be null!
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.3.15.jar:5.3.15]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235) ~[spring-orm-5.3.15.jar:5.3.15]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551) ~[spring-orm-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174) ~[spring-data-jpa-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.15.jar:5.3.15]
    at jdk.proxy4/jdk.proxy4.$Proxy113.findById(Unknown Source) ~[na:na]
    at com.example.app.service.NodeServiceImpl.saveNode(NodeServiceImpl.java:70) ~[classes/:na]
    at com.example.app.service.NodeServiceImpl$$FastClassBySpringCGLIB$$b1b25c7c.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.15.jar:5.3.15]
    at com.example.app.service.NodeServiceImpl$$EnhancerBySpringCGLIB$$3d60cf81.saveNode(<generated>) ~[classes/:na]
    at com.example.app.AppApplication.lambda$run_again$1(AppApplication.java:93) ~[classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:769) ~[spring-boot-2.6.3.jar:2.6.3]
    ... 10 common frames omitted
Caused by: java.lang.IllegalArgumentException: The given id must not be null!
    at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.15.jar:5.3.15]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findById(SimpleJpaRepository.java:301) ~[spring-data-jpa-2.6.1.jar:2.6.1]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[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:568) ~[na:na]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:639) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80) ~[spring-data-commons-2.6.1.jar:2.6.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.15.jar:5.3.15]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.15.jar:5.3.15]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.15.jar:5.3.15]
    ... 32 common frames omitted

2022-03-08 20:56:00.626  INFO 12604 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-03-08 20:56:00.630  INFO 12604 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2022-03-08 20:56:00.634  INFO 12604 --- [  restartedMain] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0

CodePudding user response:

The object node is not null. If it was, you would receive NullPointerException in the part node.getId(). What is null, is exact id. Because you haven't saved node yet and thus, the id is not generated for it and it is still null.

When you config a field with @GeneratedValue(strategy = IDENTITY), that value will be created in DB, during saving process, so before saving the object this value is still null. Meaning that you can not check the existence of a similar object by their id. You need to check other fields.

  • Related