Home > Back-end >  Spring Data CrudRepository's save throws InvocationTargetException
Spring Data CrudRepository's save throws InvocationTargetException

Time:11-02

I have spent the whole weekend trying to debug this piece of code. I have a Spring RestController :

import com.tsakirogf.schedu.model.ContactMean;
import com.tsakirogf.schedu.model.DefaultContactMean;
import com.tsakirogf.schedu.model.human.Business;
import com.tsakirogf.schedu.services.BusinessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;
import java.util.Set;

@RestController
@RequestMapping("api/v1/business/")
public class BusinessController
{
    @Autowired
    BusinessService businessService;

    @GetMapping(value = "businesss")
    Iterable<Business> list()
    {
        Iterable<Business> retVal = businessService.findAll();
        return retVal;
    }

    @RequestMapping(value = "business", method = RequestMethod.POST,  consumes = MediaType.APPLICATION_JSON_VALUE)
    Business create(@RequestBody Business business)
    {
        CollectionOfContactMethods collectionOfContact = business.getContact();
        collectionOfContact.setBusiness(business);
        Set<ContactMean> contactMeanSet = collectionOfContact.getContactMeans();
        DefaultContactMean defaultContactMeanSet = collectionOfContact.getDefaultContactMean();
        defaultContactMeanSet.getCollectionOfContactMethodsDefault().setId(collectionOfContact.getId());
        for (ContactMean element : contactMeanSet)
        {
            element.setCollectionOfContactMethods(collectionOfContact);
        }
        collectionOfContact.setDefaultContactMean(defaultContactMeanSet);
        business.setContact(collectionOfContact);

        Business retval = businessService.save(business);
        return retval;
    }

    @RequestMapping(value = "business/{id}",  method = RequestMethod.GET )
    Optional<Business> get(@PathVariable Long id)
    {
        return businessService.findById(id);
    }
}

And the service :


public interface BusinessService extends CrudRepository<Business, Long>
{
}

This is the model :

@Table(name = "business")
public class Business
{
    @Id
    @Column(name = "business_id", nullable = false)
    private Long id;

    @JsonProperty("name")
    private String name;

    @Embedded
    @JsonProperty("address")
    private Address address;

    @OneToMany(mappedBy = "business",
        cascade = CascadeType.ALL,
        fetch = FetchType.LAZY)
    @JsonProperty("operatives")
    @JsonIgnore
    Set<Professional> operatives;

    @OneToOne(mappedBy = "business",
        cascade = CascadeType.ALL,
        fetch = FetchType.LAZY,
        optional = false)
    @JsonBackReference
    @JsonProperty("contact_numbers")
    private CollectionOfContactMethods contact;

    public Business()
    {
    }

    // Getters and Setters
}

When I send a POST request like this :

Postman

Where I got the following

{ "timestamp": "2021-11-01T08:59:06.343 00:00", "status": 500, "error": "Internal Server Error", "path": "/api/v1/business/business" }

I debug and I am getting InvocationTargetException as seen below This is the controller, right before save() which seems to throw : Controller state before catch

And here is the catch : enter image description here

I found this article posted in a similar event in StackOverflow but I don't think that's what is happening in this case since I have only H2 database for now. This is application.properties file :

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.hbm2ddl.auto=create

I would appreciate any ideas. Thanks for your time.

CodePudding user response:

If you look at your last screenshot you see a message indicating that there is an id field that has no value.

In your entity you have the following declaration of your id field:

@Id
@Column(name = "business_id", nullable = false)
private Long id;

Which indicates to hibernate that it shouldn't generate a key or that there is no database assigned one. Which means you will manually need to set the value for id. If you don't you will run into this exception.

Now I assume that this was a mistake and that you actually wanted to have a sequence or auto-incremented id field. For this add the @GeneratedValue annotation to add this behavior.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE))
@Column(name = "business_id", nullable = false)
private Long id;

This will instruct hibernate to use a sequence to generate the id upon inserting the entity. If your database supports identity columns you might want to use GenerationType.IDENTITY instead of GenerationType.SEQUENCE.

  • Related