New to java and spring. Tried creating an app but was unsuccessful.I have the following entity and controller in my app. But at runtime i get an error. I posted snippets for easier reading.
staff.java
#Data
#Entity
public class Staff {
private int staff_id;
private String staff_name;
private String staff_email;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "staff")
private List<VisitRequest> visitRequest;
public String getStaff_name(){
return staff_name;
}
public void setStaff_name(String staff_name){
this.staff_name = staff_name;
}
public String getStaff_email(){
return staff_email;
}
public void setStaff_email(String staff_email){
this.staff_email = staff_email;
}
public int getStaff_id(){
return staff_id;
}
public void setStaff_id(int staff_id){
this.staff_id = staff_id;
}
}
StaffController.java
#Controller
#RestController
#RequestMapping("/staff/")
public class StaffController{
#Autowired
protected StaffRepository staffRepository;
#GetMapping("/Staff")
public List<Staff> getAllStaff() {
return staffRepository.findAll();
}
#GetMapping("/staff/{Staff_id}")
public ResponseEntity<Staff> getStaffById(#PathVariable(value = "Staff_id") Long Staff_id)
throws ResourceNotFoundException{
Staff staff = staffRepository.findById(Staff_id)
.orElseThrow(() -> new ResourceNotFoundException("Employee not Found"));
return ResponseEntity.ok().body(staff);
And the error that is thrown at runtime is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfigura
tion.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.Vportal.data.model.Staff
Please advice on what to do.
Your Staff entity lacks a member with an #Id annotation. This could be added to staff_id like follows:
#Data
#Entity
public class Staff {
#Id
private int staff_id;
....
}
Related
I am currently studying an online Spring Boot course working with Spring Data JPA.
My project includes 2 entities: BDProject and BDUser which have a many to one relationship. When attempting to find projects from user id the following exception is displayed.
EXCEPTION
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BDProjectController': Unsatisfied dependency expressed through field 'bdProjectService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BDProjectService': Unsatisfied dependency expressed through field 'bdProjectRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BDProjectRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.project.bdproject.BDProjectRepository.findByUserID(java.lang.String)! No property userID found for type BDProject!
I have spent hours trying to figure out what's causing this exception, but nothing seems to be fixing it.
MY CODE:
Entities
#Entity
public class BDUser {
#Id
private String userID;
private String bdUsername;
private String bdUserEmail;
private String bdUserPassword;
public BDUser(){
}
public BDUser(String userID, String bdUsername, String bdUserEmail, String bdUserPassword) {
super();
this.userID = userID;
this.bdUsername = bdUsername;
this.bdUserEmail = bdUserEmail;
this.bdUserPassword = bdUserPassword;
}
// getters and setters...
#Entity
public class BDProject {
#Id
private String proID;
private String proName;
private String proCodeOwner;
private String proIDs;
#ManyToOne
private BDUser bdUser;
public BDProject() {
}
public BDProject(String proID, String proName, String proCodeOwner, String proIDs, String userID) {
super();
this.proID = proID;
this.proName = proName;
this.proCodeOwner = proCodeOwner;
this.proIDs = proIDs;
this.bdUser = new BDUser(userID, "", "", "");
}
// getters and setters...
Controller
#RestController
public class BDProjectController {
#Autowired
private BDProjectService bdProjectService;
#RequestMapping("/bdusers/{userID}/bdprojects")
public List<BDProject> getAllProjects(#PathVariable String proID){
return bdProjectService.getAllProjects(proID);
}
#RequestMapping("/bdusers/{userID}/bdprojects/{proID}")
public BDProject getProject(#PathVariable String proID){
return bdProjectService.getProject(proID);
}
#RequestMapping(method= RequestMethod.POST, value="/bdusers/{userID}/bdprojects")
public void addProject(#RequestBody BDProject bdProject, #PathVariable String userID){
bdProject.setBdUser(new BDUser(userID, "", "", ""));
bdProjectService.addProject(bdProject);
}
#RequestMapping(method= RequestMethod.PUT, value="/bdusers/{userID}/bdprojects/{proID}")
public void updateProject(#RequestBody BDProject bdProject, #PathVariable String userID, #PathVariable String proID){
bdProject.setBdUser(new BDUser(userID, "", "", ""));
bdProjectService.updateProject(bdProject);
}
#RequestMapping(method= RequestMethod.DELETE, value="/bdusers/{userID}/bdprojects/{proID}")
public void deleteProject(#PathVariable String proID){
bdProjectService.deleteProject(proID);
}
}
Service
#Service
public class BDProjectService {
#Autowired
private BDProjectRepository bdProjectRepository;
public List<BDProject> getAllProjects(String userID){
List<BDProject> bdProjects = new ArrayList<>();
bdProjectRepository.findByUserID(userID).forEach(bdProjects::add);
return bdProjects;
}
public BDProject getProject(String proID){
return bdProjectRepository.findById(proID).orElse(null);
}
public void addProject(BDProject BDProject){
bdProjectRepository.save(BDProject);
}
public void updateProject(BDProject BDProject){
bdProjectRepository.save(BDProject);
}
public void deleteProject(String proID){
bdProjectRepository.deleteById(proID);
}
}
Repository
public interface BDProjectRepository extends CrudRepository<BDProject, String>{
public List<BDProject> findByUserID(String userID);
}
Any and all help is much appreciated. Thanks!
In BDProject you have property
private BDUser bdUser;
and in the repository you have:
public List<BDProject> findByUserID(String userID);
Error states that in BDProject you don't have property userID which is correct since you have bdUser.
Therefore, please change
findByUserID(String userID) to findByBdUserUserID(String userID)
You have created a BDProjectRepository interface for BDProject entity.
Please modify the method in that repository:
now: public List<BDProject> findByUserID(String userID);
should be: public List<BDProject> findByProID(String proID);
If you want to get BDProject for a specific user you can retrieve it by querying the related object as
public List<BDProject> findByBdUser_UserID(String proID);
When querying by fields in referenced object you should write it like ChildObject_ChildID
public interface BDProjectRepository extends CrudRepository<BDProject, String>
{
public List<BDProject> findByBdUser_UserID(String userID);
}
Given the following classes:
#Data #MappedSuperclass #Accessors(chain = true)
public abstract class EntidadeDeDominio {
public EntidadeDeDominio() {
type = getClass().getSimpleName();
}
#Id #GeneratedValue(strategy = GenerationType.AUTO) #TableGenerator(name="entity_gen", initialValue = 1)
private Long id = 0L;
private String type;
}
#Data #Entity
public abstract class EntidadeAuditavel extends EntidadeDeDominio {
#CreatedBy
private String criadoPor;
#CreatedDate
private Date criadoEm;
#LastModifiedBy
private String modificadoPor;
#LastModifiedDate #Temporal(TemporalType.TIMESTAMP) #JsonDeserialize(using = CustomDateDeserializer.class) #JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss'T'")
private Date modificadoEm;
}
#Data #Entity #Accessors(chain = true)
public class OrdemDeVenda extends EntidadeAuditavel {
private long numero;
#OneToMany(orphanRemoval=true, mappedBy="ordemDeVenda")
private List<ItemVenda> itemVenda;
}
#Data #Entity
public abstract class ItemVenda extends EntidadeAuditavel {
#ManyToOne
private OrdemDeVenda ordemDeVenda;
#OneToMany
private List<DestinoItemVenda> destinoItemVenda;
}
#Data #Entity #Accessors(chain = true)
public class Equipamento extends ItemVenda {
private long numero;
private String modelo;
#OneToMany(orphanRemoval = true, mappedBy="equipamento")
private List<Modulo> modulo;
public String toString() {
return String.valueOf(numero);
}
}
#Data #Entity
public class ProdutoGenerico extends ItemVenda {
private String descricao;
#OneToMany(orphanRemoval = true)
private List<Imposto> imposto;
private double preco_unitario;
public String toString() {
return descricao;
}
}
By being it's child, they all inherit a type attribute from the class EntidadeDeDominio and this attribute is also sent by the form by using a hidden field.
And, to resume a little, some info about the form:
Parameters received from the form when the object is an ProdutoGenerico
[id, type, numero, itemVenda[0].type, itemVenda[0].descricao]
Some of the parameters received from the form when the object is an Equipamento
[id, type, numero, itemVenda[0].type, itemVenda[0].modelo]
And the problem:
Spring, during DataBind (to a #ModelAttribute OrdemDeVenda object), fails to fill the List<ItemVenda> itemVenda because because ItemVenda is an abstract class.
And the current workaround:
After several seriously painful headaches and with the help of another post (How to bind a subclass of an abstract class in a Spring-MVC method?) I managed to get the following code to work (hardcoding the routine to use the 'type' attribute to instantiate the correct class and populate the list).
#InitBinder
public void registerConversionServices(WebDataBinder binder, HttpServletRequest request) {
Object nonCasted = binder.getTarget();
if(nonCasted == null || !(nonCasted instanceof OrdemDeVenda)) {
return;
}
OrdemDeVenda ov = (OrdemDeVenda) nonCasted;
List<String> params = Collections.list(request.getParameterNames());
long cnt = params.stream().filter(p -> p.contains("[")).map(p -> p.substring(0, p.indexOf("]") + 1)).distinct().count();
if(cnt > 0) {
List<String> types = params.stream().filter(p -> p.startsWith("itemVenda") && p.endsWith("type")).map(p -> request.getParameter(p)).collect(Collectors.toList());
for(int i = 0; i < cnt; i++) {
try {
Class<? extends ItemVenda> clz = (Class<? extends ItemVenda>) Class.forName(ItemVenda.class.getPackage().getName() + "." + types.get(i));
if(CollectionUtils.isEmpty(ov.getItemVenda())) {
ov.setItemVenda(new ArrayList<>());
}
ov.getItemVenda().add(clz.newInstance());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
My question is: Is there a cleanner way of achieving the same result? Like some sort of custom property editor?
P.S.: I tried very very hard to use some custom property editors but they were never invoked by spring. I tried stuff like 'registerCustomEditor(ItemVenda.class, myEditor), registerCustomEditor(List.class, myEditor), registerCustomEditor(List.class, 'itemVenda', myEditor), registerCustomEditor(ItemVenda.class, 'itemVenda', myEditor), ..., ... but none of them worked.
Exception:
Invalid property 'itemVenda[0]' of bean class [com.richard.weger.rerp.domain.OrdemDeVenda]: Illegal attempt to get property 'itemVenda' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'itemVenda' of bean class [com.richard.weger.rerp.domain.OrdemDeVenda]: Could not instantiate property type [com.richard.weger.rerp.domain.ItemVenda] to auto-grow nested property path; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.richard.weger.rerp.domain.ItemVenda]: Is it an abstract class?; nested exception is java.lang.InstantiationException
org.springframework.beans.InvalidPropertyException: Invalid property 'itemVenda[0]' of bean class [com.richard.weger.rerp.domain.OrdemDeVenda]: Illegal attempt to get property 'itemVenda' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'itemVenda' of bean class [com.richard.weger.rerp.domain.OrdemDeVenda]: Could not instantiate property type [com.richard.weger.rerp.domain.ItemVenda] to auto-grow nested property path; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.richard.weger.rerp.domain.ItemVenda]: Is it an abstract class?; nested exception is java.lang.InstantiationException
I have Entity
#Entity
#Table(name = "messages")
public class Message {
...
#Column(name = "isVisibleForSender")
private boolean isVisibleForSender;
}
and Spring Data repository
#Repository
#Transactional
public interface MessageCRUDRepository extends JpaRepository<Message, Long> {
...
public boolean getVisibleForRecipient(boolean isVisibleForRecipient);
}
When compiling, the program throws me an exception Caused by: org.springframework.data.mapping.PropertyReferenceException: No property getIsVisibleForRecipient found for type Message!
After seeing your comments, you have the wrong method name:
#Entity
#Table(name = "messages")
public class Message {
#Column(name = "isVisibleForRecipient")
private boolean visibleForRecipient;
}
And for the repo:
interface MessageCRUDRepository extends JpaRepository<Message, Long> {
List<Message> findByVisibleForRecipient(Boolean bool);
}
Make sure you have getters and setters for the visibleForRecipient field in the message object
I am trying to implement something for converting between my Entities and DTO.
I have base class for my DTOs (called Models):
public class BaseModel<Entity> implements Model<Entity> {
#Override
public Entity toEntity(Class<Entity> entityClass) {
Entity entityInstance = BeanUtils.instantiate(entityClass);
BeanUtils.copyProperties(this, entityInstance);
return entityInstance;
}
}
But following test doesn't passes:
public class BaseModelTest {
#Entity
public class SomeEntity {
#Id
private Long id;
private String name;
public SomeEntity() {
}
public SomeEntity(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
#Test
public void toEntity_givenEntityClass_shouldCreateNewInstance() throws Exception {
//given
BaseModel<SomeEntity> model = new BaseModel();
//when
SomeEntity entity = model.toEntity(SomeEntity.class);
//then
assertNotNull(entity);
}
}
I got exception: (despite the fact, under debugger I see all ctors):
org.springframework.beans.BeanInstantiationException: Failed to instantiate [package.BaseModelTest$SomeEntity]: Is it an abstract class?; nested exception is java.lang.InstantiationException: package.BaseModelTest$SomeEntity
Caused by: java.lang.InstantiationException: package.BaseModelTest$SomeEntity
Caused by: java.lang.NoSuchMethodException: package.BaseModelTest$SomeEntity.<init>()
Currently to create a new SomeEntity instance you need an instance of the enclosing BaseModelTest class. SomeEntity should be an inner static class. Replace:
public class SomeEntity {
with
public static class SomeEntity {
BTW. There is no point in having a DTO class if it maps 1-1 to a model class, it does not add any value, it is only boilerplate code.
So I have this HATEOAS entity.
#Entity
#Table(name="users")
public class User extends ResourceSupport {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long id;
public User() {
}
public Long getId() {
return new Long(id);
}
public void setId(Long id) {
this.id = id.longValue();
}
}
My entity has an id of type long, but HATEOAS's ResourceSupport requires that getId return a Link.
The entity has a Long id because the db has a long id, and it is a persisted entity. How can I implement this entity with HATEOAS?
Check out the "Link Builder" section of the documentation:
http://docs.spring.io/spring-hateoas/docs/current/reference/html/#fundamentals.obtaining-links.builder
There, it describes how to use a ControllerLinkBuilder to create the Link using a separate controller class. Your User Object would implement Identifiable<Long>, as the example in the page above shows.
You can create one BeanResource bean which extends ResourceSupport bean like.
#JsonIgnoreProperties({ "id" })
public class BeanResource extends ResourceSupport {
#JsonUnwrapped
private Object resorce;
public Resource(Object resorce) {
this.resorce = resorce;
}
public Object getResorce() {
return resorce;
}
}
just Unwrap resource instance property so that BeanResource bean will render json like user bean along with ResourceSupport bean will render link json object,
after that you can create assembler like this.
public class UserAssembler extends ResourceAssemblerSupport<User, BeanResource> {
public UserAssembler() {
super(User.class, BeanResource.class);
}
#Override
public Resource toResource(User user) {
Resource userResource = new Resource(user);
try {
Link selfLink = linkTo(
methodOn(UserController.class).getUser(user.getId()))
.withSelfRel();
userResource.add(selfLink);
} catch (EntityDoseNotExistException e) {
e.printStackTrace();
}
return userResource;
}
}
and in controller just attach Resource bean which contains user bean like
#RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
public ResponseEntity<Resource> getUser(#PathVariable String userId)
throws EntityDoseNotExistException {
User user = userService.getUser(userId);
Resource userResource = userAssembler.toResource(user);
return new ResponseEntity<Resource>(userResource, HttpStatus.OK);
}