Object is not an instance of a persistable class warning with Spring boot and Neo4j - spring-boot

I have a pretty straightforward class called User which is supposed to create user objects containing user information and login details.
package com.example.domain;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import java.util.HashSet;
import java.util.Set;
#NodeEntity
public class User {
public User() {}
#GraphId
private Long id;
private String username;
private String password;
private String name;
private String email;
private String Role;
#Relationship(type="BELONGS_TO", direction = Relationship.INCOMING)
Set<Item> items = new HashSet<>();
public User(String name, String username, String password, String email) {
this.name = name;
this.username = username;
this.password = password;
this.email = email;
}
// Getters and setters below for private fields...
}
The controller creating the object looks like this:
#RequestMapping(value = "/register",method = RequestMethod.POST)
public String register(Model model,
#ModelAttribute(value="name") String name,
#ModelAttribute(value="username") String username,
#ModelAttribute(value="email") String email,
#ModelAttribute(value="password") String password,
#ModelAttribute(value="confirmPassword") String confirmPassword) {
if(!password.equals(confirmPassword)) {
model.addAttribute("error", true);
return "register";
}
User userEntity=new User(name,username,password,email);
userManagementService.save(userEntity); //<------The object is created but the error occures during persistance
return "login";
}
and my user management service looks like this:
public interface UserManagementService {
List<User> listAll();
User save(User user);
User findUser(String username);
}
What makes the User class, not an instance of a persistable class. What are the characteristics of a persistable class and how can I make User a persistable class?

Have you configured the OGM somewhere? Either in a Java configuration or in a ogm.properties file? You'll need to specify the driver type and tell the SessionFactory where to look for your domain objects.
OGM config reference: https://neo4j.com/docs/ogm-manual/2.1/reference/#reference:configuration
SessionFactory config reference: https://neo4j.com/docs/ogm-manual/2.1/reference/#reference:connecting:session-factory

Related

How can save order detail associated with the user and How can I return order data associated with the user details based the url parameters?

I have created the User and Order entities as bellow. What I want to achieve is that if http://localhost:8080/users/username? is given I want to return only the user detail based on username provided. if http://localhost:8080/users/username?detail=true, I want to return user detail and order details for the username provided. How can I achieve this?
User.java
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String userName;
private String password;
private String firstName;
private String lastName;
private String gender;
private String lastLoggedIn;
#OneToMany
List<Order> listOfOrder;
//constructors
//getter and setter
}
Order.java
#Entity
public class Order
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private float amount;
private String createdAt;
private String deliveredDate;
//constructors
//getter and setter
}
Controller.java
//CREATE CUSTOMER
#RequestMapping(method = POST, value = "/create")
public ResponseEntity createCustomerDetails(#RequestParam String userName, String password, String firstName,
String lastName, String gender) {
String lastLogged = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
User user = new User(userName, password, firstName, lastName, gender, lastLogged);
userRepository.save(user);
return ResponseEntity.status(OK).body(user.getId() + " User were successfully saved");
}
//CREATE ORDER
#RequestMapping(method = POST, value = "/order/{userName}")
public ResponseEntity createOrder(#PathVariable ("userName") String userName, #RequestParam float amount)
{
String createdAt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
String deliveredDate = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
User user = orderService.findUser(userName);
if (!user.equals(null))
{
Order order = new Order(amount,createdAt,deliveredDate);
user.getListOfOrder().add(order);
return ResponseEntity.status(OK).body("order details were saved under "+user.getUserName() + " "+user.getFirstName());
}
return ResponseEntity.status(NOT_FOUND).body(null + " was not found");
}
//GET THE USER DETAILS
#RequestMapping(method = GET, value = "/users/{userName}")
public ResponseEntity getUserDetail(#PathVariable("userName") String userName,
#RequestParam(defaultValue ="none", required = false) String detail) {
if (!detail.equals("none")){
return .....;
}else {
return ........;
}
}
UserRepository
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUserName(String userName);
}
If you're ok with doing the serialization manually, you can employ JsonView to determine what gets serialized.
https://www.baeldung.com/jackson-json-view-annotation
User.java
import com.fasterxml.jackson.annotation.JsonView;
public class User {
#JsonView(Views.Lite.class)
private String name;
#JsonView(Views.Full.class)
private List<Order> orders;
}
Views.java
public class Views {
public static class Lite {}
public static class Full extends Lite {}
}
UserController.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
private ObjectMapper mapper;
#GetMapping("/user/{username}")
public ResponseEntity<String> getUserDetail(#PathVariable String username, #RequestParam(required = false) String detail) throws JsonProcessingException {
User user = userRepository.findByUserName(username);
Class viewClass = Views.Lite.class;
if (!StringUtils.isEmpty(detail)) {
viewClass = Views.Full.class;
}
return ResponseEntity.status(HttpStatus.OK)
.body(mapper.writerWithView(viewClass).writeValueAsString(user));
}
}

why I can't use string as id

I am trying to create a user model with a CrudRepository:
#Entity
public class User {
#Id
#GeneratedValue
private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
public interface UserRepository extends CrudRepository<User, String> {
}
However I got an 500 error every time I call findOne():
#Controller
public class UserController {
#Autowired
private UserRepository users;
#Override
#RequestMapping(value="/register", method=RequestMethod.POST)
public #ResponseBody User register(#RequestBody User userToRegister) {
String username = userToRegister.getUsername();
User user = users.findOne(id);
if (user != null) {
return null;
}
User registeredUser = users.save(userToRegister);
return registeredUser;
}
}
However if I just switch to an long type id instead of username itself then everything works. I think it's common to use string as id. So how to make this work?
I use the embedded hsql database. I didn't wrote any sql code.
The problem is that String username; is annotated with both #Id and #GeneratedValue. #Id means that is should be a primary key, fine it can be a String. But #GeneratedValue means that you want the system to automatically generate a new key when you create a new record. That's easy when the primary key is integer, all databases have a notion of sequence (even if the syntax is not always the same). But if you want String automatically generated keys, you will have do define your own custom generator.
Or if you have no reason for the #GeneratedValue annotation, simply remove it as suggested by Bohuslav Burghardt
Use column annotation like below by putting nullable False.
#Id
#GeneratedValue
#Column(name = "username", nullable = false)
private String username;

Returning returned model object to json String using spring data jpa with hibernate

I am using spring data jpa with hibernate
This is my dao interface
#Repository
public interface IUserDAO extends JpaRepository<User, Integer>{
User findByUsername( final String username );
}
This is my User class
Entity
#Table(name="USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="ID", nullable = false)
private int id;
#Column(name="USERNAME", nullable = false)
private String username;
#Column(name="NAME", nullable = false)
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This is my UserImplClass
This is my UserImplClass{
#Autowired
private IUserDAO iUserDAO;
public String findUserByUserName(String username) {
User user =iUserDAO.findByUsername(username);
Convert user to json object from framework level automatically
// i can add my one implemenation of converting user to json here ,but i want to achieve it from framework so that my code is not scattered on every service level
return "jsonStringOfUserObject"
}
Is it possible with spring data jpa with hibernate so that i do not have to write code for converting java object to json string in every service level?
I am using spring ,therefore i want to achieve it from spring .
You have two options to do what you want:
1) If you plan on returning this Object as an HTTP Response, and you use Spring MVC with Controllers you can annotate your controller method as follows:
public #ResponseBody User getUser(){
return userImplClass.findUserByUserName("yourusername");
}
2) If you want the UserImplClass itself to return a JSON String (which I do't recommend, but I leave you the decision), you can use Jackson Object Mapper to do it for you (you can inject it if you declare it as a bean on your configuration xml, or create a new instance of it, I personally prefer injecting it with #Autowired)
public String findUserByUserName(String username) {
User user =iUserDAO.findByUsername(username);
ObjectMapper mapper = new ObjectMapper(); // no need to do this if you inject via #Autowired
return mapper.writeValueAsString(user);
}

How to handle two database insertions fom a single form in spring/ hibernate?

I have 3 model classes,
User.java
public class UserData {
private Integer userID;
private String userName;
private String userPassword;
//getters and setters..
and Permission class like..
Permission.java
public class PermissionsData {
private Integer permissionID;
private Integer userID;
private Integer moduleID;
private boolean permissionIsReadOnly;
private boolean permissionIsModify;
private boolean permissionIsFull;
//getters and setters
amd module class like,
module.java
public class ModuleData {
private Integer modId;
private String modName;
I have some modules in my database. When i am creating a new user, i had listed those modules and had added checkboxes to set permissions. When submitting the form, i need to insert user data to user table and his permissions for each module to the Permission table.
Now i had implemented only inserting roles to the database.. my controller is like..
#RequestMapping(value = "/addRole")
public ModelAndView addNewRole()
{
ModelAndView mav = new ModelAndView("addNewRole");
RoleData role = new RoleData();
mav.getModelMap().put("roleDataObj", role);
List<ModuleData> moduleList = moduleService.getAllModules();
mav.getModelMap().addAttribute("ModuleList", moduleList);
return mav;
}
How can i achieve to add data to two tables on one submit?? i would also like to know about the mapping betwewen modules and permission
I am really new to this spring and hibernate. So plz guide me with sample codes..
Thanks in advance.
if you have set cascading in the mapping
#Cascade(Cascade.all)
private List<Permission> permissions;
it is as simple as
public void saveNewUser(...)
{
User user = new User();
// fill properties
Permission p = new Permission();
// fill properties
user.getPermissions().add(p);
session.save(user);
}
Update: the code above would be possible using a class structure like. the important part is the collection/map of permissions each user has per modul
public class Permission {
private boolean IsReadOnly;
private boolean IsModify;
private boolean IsFull;
}
public class Module {
private Integer id;
private String name;
}
public class User {
private Integer id;
private String name;
private String password;
private Map<Module, Permission> permissions;
}
and mapping
<class name="User">
...
<map name="permissions" cascade="all">
<key column="UserId"/>
<index-many-to-many column="ModuleId" class="Module"/>
<composite-element class="Permission">
<property name="IsReadOnly"/>
<property name="IsModify"/>
<property name="IsFull"/>
</composite-element>
</map>

spring data mongodb MongoRepository.save(T entity) method not working?

The code is listed below:
#Document
#XmlRootElement
public class User {
#Indexed(unique=true)
private String username;
private String firstName;
private String lastName;
private String password;
...... omit setters and getters
}
public interface UserRepo extends MongoRepository<User, String>{
}
public User update(User user) {
User existingUser = userRepo.findByUsername(user.getUsername());
if (existingUser == null) {
return null;
}
existingUser.setFirstName(user.getFirstName());
existingUser.setLastName(user.getLastName());
return userRepo.save(existingUser);
}
when update method invoked, the finds the user based on username and finishes without any exceptions, the returned User obj has all updated value but the underlying mongodb document is not changed! Can anyone help? Thanks.
you need an Id field with #Id annotation

Resources