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 :
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 :
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
.