Home > Enterprise >  Hibernate AssertionFailure null identifier postgresql db
Hibernate AssertionFailure null identifier postgresql db

Time:11-08

here's one more of these as I've read through the rest and tried to implement the fixes, but to no avail. My problem is that my User object is being saved correctly (I can see them pop into the database), but my UserPreferences object throws the error. This is really strange, as I'm doing everything explicitly right now, and know, for sure, that at the time of the "save" call to the repository, no fields in the Preferences object is null. Least of all the "user" and "user_id" (PKEY).

Here's the class for UserPreferences:

package gbw.TheScheduler.models;

@Entity
@Table(name="user_preferences")
@JsonSerialize
public class UserPreferences implements Serializable {

    static final long serialVersionUID = 828325321321L;
    public static UserPreferences getDefault(User user){
        return new UserPreferences(user,60);
    }

    public UserPreferences(){}
    public UserPreferences(User user, int hours){
        this.user = user;
        this.userId = user.getId();
        this.hours = hours;
        this.timeslots = new HashSet<>();
    }

    @Id
    @Column(name = "user_id")
    private int userId;
    private int hours;

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    @JoinColumn(name = "user_id")
    private User user;

    @OneToMany(mappedBy="preferences", fetch = FetchType.LAZY)
    private Set<PreferencesTimeSlot> timeslots = new HashSet<>();

    @JsonProperty
    public int getHours(){
        return hours;
    }

    @JsonProperty
    public Set<PreferencesTimeSlot> getTimeslots(){
        return timeslots;
    }

    public void setUser(User user){
        this.user = user;
        this.userId = user.getId();
    }
    public void setHours(int i){
        this.hours = i;
    }
    public void setTimeslots(Set<PreferencesTimeSlot> list){
        this.timeslots = list;
    }

    @JsonProperty
    public int getId() {
        return user.getId();
    }
}

Here's my "User" class:

package gbw.TheScheduler.models;

import static gbw.TheScheduler.util.ArrayUtil.*;

@Entity
@Table(name = "users")
@JsonSerialize
public class User implements Serializable {

    static final long serialVersionUID = 321321321321L;

    @Id
    private int id;
    @JsonProperty
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @PrimaryKeyJoinColumn
    private UserPreferences userPreferences;

    @JsonProperty
    @ManyToMany(fetch = FetchType.LAZY)
    private Set<MonthlySchedule> schedules = new HashSet<>();

    @JsonProperty("first_name")
    @Column(name = "first_name")
    private String firstName;
    @JsonProperty("last_name")
    @Column(name = "last_name")
    private String lastName;
    @JsonProperty("initials")
    @Column(name = "initials")
    private String initials;
    @JsonProperty("email")
    @Column(name = "email")
    private String email;
    @JsonProperty("password")
    @Column(name = "password")
    private String password; 
    @JsonProperty("admin")
    @Column(name = "admin")
    private boolean admin;

    public User(@JsonProperty("initials") String initials, @JsonProperty("password") String password,
                @JsonProperty("admin") boolean state, @JsonProperty("email") String email, @JsonProperty("first_name") String firstName,
                @JsonProperty("last_name") String lastName){
        this.initials = initials;
        this.password = password;
        this.admin = state;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString(){
        return initials   " "   password;
    }

    @JsonProperty
    public Set<MonthlySchedule> getSchedules(){
        return schedules;
    }

    @JsonProperty
    public void setSchedules(Set<MonthlySchedule> schedules){
        this.schedules = schedules;
    }

    @JsonProperty
    public UserPreferences getPreferences(){
        return userPreferences;
    }
    @JsonProperty
    public void setPreferences(UserPreferences pref){
        this.userPreferences = pref;
    }

    @JsonProperty
    public int getId() {
        return id;
    }
    @JsonProperty
    public void setAdmin(boolean state){
        admin = state;
    }

    @JsonProperty
    public boolean isAdmin() {
        return admin;
    }

    public void setId(int id) {
        this.id = id;
    }
    @JsonProperty
    public String getFirstName() {
        return firstName;
    }
    @JsonProperty
    public void setFirstName(String name) {
        this.firstName = name;
    }
    @JsonProperty
    public String getInitials() {
        return initials;
    }

    @JsonProperty
    public String getLastName(){
        return lastName;
    }
    @JsonProperty
    public void setInitials(String initials) {
        this.initials = initials;
    }
    @JsonProperty
    public String getEmail() {
        return email;
    }

    @JsonProperty
    public String getPassword() {
        return password;
    }
    @JsonProperty
    public void setEmail(String email) {
        this.email = email;
    }

    public User(){}
    @JsonProperty
    public void setPassword(String password) {
        this.password = password;
    }
    @JsonProperty
    public void setLastName(String value) {
        this.lastName = value;
    }
}

Here's my UserController, where the issue occurs in line 68 according to the stacktrace:

@RequestMapping(path=path "/add/{username}/{password}", method = RequestMethod.POST) // Map ONLY POST Requests
    public @ResponseBody ResponseEntity<User> addNewUser (@RequestBody String requestText, @RequestHeader(required = false) String headerText, @PathVariable String username, @PathVariable String password) {
        UserService.UserValidationResult validationBaseAccess = userService.validateUserAdminAccess(username,password);
        if(validationBaseAccess.error() != null){
            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }
        JSONWrapper parsed = new JSONWrapper(requestText);
        User user = new User(
                parsed.get("initials"),
                parsed.get("password"),
                BooleanUtil.parseOr(parsed.get("admin"), false),
                parsed.get("email"),
                parsed.getOr("first_name","Guest"),
                parsed.getOr("last_name","User")
                );
        user.setId(userService.getValidId());

        UserPreferences prefs = UserPreferences.getDefault(user);
        User asSaved = userService.save(user);
        prefRepo.save(prefs);             <---------Issue occurs right here!
        asSaved.setPreferences(prefs);
        return new ResponseEntity<>(asSaved,HttpStatus.OK);
    }

And the stacktrace:

org.hibernate.AssertionFailure: null identifier
    at org.hibernate.engine.spi.EntityKey.<init>(EntityKey.java:51) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.internal.AbstractSharedSessionContract.generateEntityKey(AbstractSharedSessionContract.java:559) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.type.OneToOneType.isNull(OneToOneType.java:108) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.type.EntityType.resolve(EntityType.java:463) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.type.EntityType.resolve(EntityType.java:458) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.type.EntityType.replace(EntityType.java:359) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.type.AbstractType.replace(AbstractType.java:164) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.type.TypeHelper.replace(TypeHelper.java:205) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:487) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:241) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:318) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:172) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:70) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:829) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:816) ~[hibernate-core-5.6.11.Final.jar:5.6.11.Final]
    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.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-5.3.23.jar:5.3.23]
    at jdk.proxy4/jdk.proxy4.$Proxy111.merge(Unknown Source) ~[na:na]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:669) ~[spring-data-jpa-2.7.3.jar:2.7.3]
    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.7.3.jar:2.7.3]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:530) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:286) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:640) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:139) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:81) ~[spring-data-commons-2.7.3.jar:2.7.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.23.jar:5.3.23]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.23.jar:5.3.23]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174) ~[spring-data-jpa-2.7.3.jar:2.7.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.23.jar:5.3.23]
    at jdk.proxy4/jdk.proxy4.$Proxy120.save(Unknown Source) ~[na:na]
    at gbw.TheScheduler.controllers.UserController.addNewUser(UserController.java:68) ~[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.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

And finally my application.properties:

server.port=6969
security.ignored=/**
management.security.enabled=false
spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.jpa.show-sql=false
spring.jpa.open-in-view=false
spring.datasource.username=postgres
spring.datasource.password=definetlyMyPassword
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL81Dialect
spring.main.allow-bean-definition-overriding=true

If you know anything, please. I've been stuck with this for way too long for just a fun little side-project. :(

CodePudding user response:

I found out, that my one to one mapping was wrong and my auto generated ID's went awry somewhere along the road. I think its a bug where hibernate doesn't realize that an autogenerated id should actually be null in the case of a new user.

Although confusing to look at, my one to one mapping ended up looking like this:

In User (parent):

@Id
@Column(name = "id")
private Long id;

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name="id"<!CHILD ID-FIELD!>, referencedColumnName = "id"<!PARENT ID-FIELD!>)
private UserPreferences userPreferences;

In UserPreferences (child):

@Id
@Column(name = "id")
private Long id;

@OneToOne(mappedBy="userPreferences", fetch = FetchType.EAGER)
private User user;

Do note that I'm doing a lot of this mapping manually as well. So, if you're relying more on Hibernate's native way of doing things, this might very well not work for you. (See my UserController to see what I mean).

  • Related