EJB webservice, entity is not mapped error - java

I have entity class User
#Entity(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(unique = true, nullable = false)
private String email;
/** skipped **/
And stateless EJB DAO class(I am using jpa/hibernate) with method
#Override
public User findByEmail(String name) {
TypedQuery<User> query = entityManager.createQuery("from User where email= :email", User.class);
query.setParameter("email", name);
return query.getSingleResult();
}
When I execute this method from page(using jsf), it works fine. The problem occurse when I execute this method from WebService EJB bean. I've got following exception
org.hibernate.hql.internal.ast.QuerySyntaxException: User is not mapped [from User where email= :email]
My web service is very simple:
#Stateless(name = "webServiceBean")
#WebService(serviceName = "webService")
public class MyWebService{
#EJB
private UserDao dao;
public String findUser(String email) {
return dao.findByEmail(email);
}
}
Application is deployed on JBoss7. I am using EJB 3.1 and hibernate 4.3
Does anybody knows what is the reason of this exception? And why it occurs only in WebService?

Make sure User, along with the package name, is listed in hibernate config file.
Either use just #Entity or #Entity(name = "User"). You have named your entity as user but in your query trying to refer to it as User.
Check the docs for the #Entity's name attribute.
public abstract java.lang.String name
(Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to the entity in queries. The name must not be a reserved literal in the Java Persistence query language.

Related

Evaluate lazily with spring-data

I would like to have the roles set fetch lazily. Hibernate fetchType.Lazy doesn't work for this cases, where spring data is used. I 've been trying lots of possibilities like Entitygraph but none of them works on this, or I'm using them wrong.
I have the next classes:
A class User:
#Entity
#JsonRootName(value = "user")
#Table(name = "web_users", schema = "t_dw_comercial")
public class User {
#Id
private int userId;
private String fullName;
#OneToMany(fetch=FetchType.LAZY)
#JoinTable(name="web_users_roles",
joinColumns = {#JoinColumn(name="user_id")},
inverseJoinColumns = {#JoinColumn(name="role_id")}
)
private List<Role> roles;
}
A class Role:
#Entity
#JsonRootName(value = "roles")
#Table(name = "web_roles", schema = "t_dw_comercial")
public class Role {
#Id
private int roleId;
private String roleName;
}
Service:
#Service
public class UserService implements IUserService{
#Autowired
UserRepository repository;
public User findUserByLdapId(String loginName) {
return repository.findUserByLdapId(loginName);
}
}
Repository:
#Repository
public interface UserRepository extends CrudRepository<User, Long>{
#Query("SELECT u FROM User u where u.ldapId= ?1")
public User findUserByLdapId(String loginName);
}
Controller:
#Controller
#RestController
public class UserController {
#Autowired
private IUserService userService;
#CrossOrigin
#RequestMapping(value = "/dashboard", params = {"user"}, method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<User> getUser(#RequestParam(value = "user") String ldapId) {
User user = userService.findUserByLdapId(ldapId);
if(user == null)
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
return new ResponseEntity<>(user, HttpStatus.OK);
};
}
So a json would looks like:
{
"user": {
"userId": 1,
"fullName": "Carolina Ponce",
"roles":[]
}
}
Thanks in advance!
It seems you're asking for two different things: how to fetch #OneToMany association lazily (which should work out of the box) and how to make your JSON look like the above (which has nothing to do with how your JPA entity fetching is configured).
If you serialize your entity using Jackson, by default all the fields will get serialized, including those that are fetched lazily. If the persistence context is still open when you begin to serialize the entities, Jackson will simply trigger lazy loading by accessing the property. As a result, regardless of whether you use FetchType.EAGER or FetchType.LAZY, roles will be included in the result (I assume it is the case, since you'd be getting a LazyInitializationException if the context was closed).
The solution is, simply, to tell Jackson to refrain from serializing roles using #JsonIgnore if you don't want the property in the result.
First of all Hibernate and Spring Data are totally different tools designed for different purposes and they work with each other just fine. You can read more about the differences between both here: What Is the Difference Between Hibernate and Spring Data JPA?
Spring Data has nothing to do with how you fetch entity's related collections, Hibernate, as an implementation of JPA, does.
I assume you indeed fetch your collection lazily and that happens during serialization of your entity so the mechanism works as it should.
I suggest you to create some sort of DTO object that you could return from your controller rather than returning an entity. It seems like you don't want to expose user's roles so creating a DTO without roles may be a good idea. Other solution is to instruct Jackson to ommit roles property during serialization using #JsonIgnore annotation.

Why does Hibernate allow me to insert a null value on a foreign key constraint?

I am experimenting with jpa and hibernate relations. I'm using a table named users and a table named emails. A user can have many emails.
When I run my Spring boot application along with the following code I get one email record in my h2 database. The email_address of this record is testAddress and the user_username column of this record is null. The user_username column is listed as a foreign key on the emails table. My question is, why is emailRepository.save(email1) successful when there is no corresponding user in the database?
#Entity
#Table(name = "emails")
public class Email {
#Id
private String emailAddress;
#ManyToOne
private User user;
...
}
#Entity
#Table(name = "users")
public class User {
#Id
private String username;
#OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
private Set<Email> emails;
...
}
public interface UserRepository extends JpaRepository<User, String> {
}
public interface EmailRepository extends JpaRepository<Email, String> {
}
#Component
public class UserRepositoryCommandLineRunner implements CommandLineRunner {
#Autowired
private EmailRepository emailRepository;
public void run(String... args) throws Exception {
Email email1 = new Email();
email1.setEmailAddress("testAddress");
emailRepository.save(email1);
}
}
Take a look at the documentation of the JoinColumn annotation:
https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html#nullable()
It is mentioned:
If the JoinColumn annotation itself is defaulted, a single join column
is assumed and the default values apply.
Since you did not specify a JoinColumn in your ManyToOne mapping, then Hibernate would assume the default JoinColumn. If you take a look at the JoinColumn.nullable attribute, it is defaulted to true. Thus, when Hibernate generates your schema, the foreign key column is by default NULLABLE.
You may need to explicitly add a #JoinColumn annotation on top of your #ManyToOne mapping and set its nullable attribute to false.
#ManyToOne
#JoinColumn(nullable=false)
private User user;
This way, it'll throw out an error when you try to insert email without a user.

Spring-Boot subclassing User and findUserByUsername

I'm aiming for subclassing Spring's User class, as it already has the standard attributes. One question arises as to how am I supposed to implement a CrudRepository that refers to properties in the User class?
Specifically I'm wondering about the most common use case, namely the findUserByUsername (called by UserDetailsService.loadUserByUsername). Here's some code...
#Entity
#SequenceGenerator(name = "generator", initialValue = 1)
public class AppUser extends User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
private long id;
public AppUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
public long getId() {
return id;
}
}
Attempting to create the CrudRepository normally, will fail miserably with Could not query metamodel upon startup. This makes sense, because the username attribute is not inherited directly to my subclass and User is obviously not marked as #Entity.
#Transactional
#Repository
public interface UserRepository extends CrudRepository<AppUser, Long> {
AppUser findByUsername(String username);
}
Error message upon startup
Error creating bean with name 'userRepository': Invocation of init
method failed; nested exception is java.lang.IllegalArgumentException:
Could not create query metamodel for method public abstract
se.riee.user.AppUser
se.riee.user.UserRepository.findByUsername(java.lang.String)!

NucleusUserException: Cannot access field on entity extending mapped superclass

I am running into a NucleusUserException while querying my google datastore instance. I am querying for a field that exists on a MappedSuperclass on the class that extends it. Here is my abstract class that contains the field I am interested in:
#Entity
#MappedSuperclass
#JsonIgnoreProperties({ "password" })
public abstract class AbstractUser implements User {
#Persistent
protected String emailAddress;
public void setEmailAddress(String email) {
this.emailAddress = email;
}
public String getEmailAddress() {
return this.emailAddress;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long key;
//Other stuff.
}
The concrete instance looks like this:
#Entity
public class Client extends AbstractUser {
//Things that only clients have.
}
My query that is failing looks like this:
List existingUsersWithEmail = manager
.createQuery(
"SELECT c from Client AS c WHERE c.emailaddress = :mail")
.setParameter("mail", request.getEmailAddress())
.getResultList();
The exception is this:
Cannot access field emailaddress on type org.workouthound.user.Client
org.datanucleus.exceptions.NucleusUserException: Cannot access field emailaddress on type org.workouthound.user.Client
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:552)
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:529)
at org.datanucleus.query.symbol.SymbolTable.getType(SymbolTable.java:118)
at org.datanucleus.query.expression.PrimaryExpression.bind(PrimaryExpression.java:118)
at org.datanucleus.query.expression.DyadicExpression.bind(DyadicExpression.java:85)
at org.datanucleus.query.compiler.JavaQueryCompiler.compileFilter(JavaQueryCompiler.java:299)
at org.datanucleus.query.compiler.JPQLCompiler.compile(JPQLCompiler.java:75)
at org.datanucleus.store.query.AbstractJPQLQuery.compileInternal(AbstractJPQLQuery.java:246)
at org.datanucleus.store.query.Query.setImplicitParameter(Query.java:690)
at org.datanucleus.jpa.JPAQuery.setParameter(JPAQuery.java:428)
at org.workouthound.rest.client.UserResources.emailIsRegistered(UserResources.java:55)
at org.workouthound.rest.client.UserResources.createClient(UserResources.java:33)
I am new to DataNucleus and Google Data Store. I attempted to follow the tutorial as outlined here however I very well could have missed something. Please let me know as additional information is necessary.
UPDATE:
If I change the field name to email as well as the getters, setters and query, it works...why?

Hibernate table mappings with annotations

I'm just getting started with Spring/Hibernate and I'm trying to understand how hibernate maps entities to tables. Right now I'm working with the following classes to test out CRUD operation with hibernate:
#Entity
#Table(name = "Users")
public class UserEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String firstName;
private String lastName;
private int age;
//Getters, setters, etc.
}
#Repository
public class UserDAOImpl implements UserDAO {
#Autowired
HibernateTemplate hibernateTemplate;
#Override
public UserEntity getUser(String firstName, String lastName) {
List<UserEntity> users = hibernateTemplate.find("from UserEntity u where u.firstName = ? and u.lastName = ?", firstName, lastName);
return (users.size() == 0 ? null : users.get(0));
}
#Override
public void saveOrUpdate(UserEntity user) {
hibernateTemplate.saveOrUpdate(user);
}
}
The code above is working fine, but I'm confused how UserEntity is being mapped to a table. More specifically, when calling hibernateTemplate.find("from UserEntity u where u.firstName = ? and u.lastName = ?", firstName, lastName) I get the following message in the log:
Hibernate: select userentity0_.id as id0_, userentity0_.age as age0_, userentity0_.firstName as firstName0_, userentity0_.lastName as lastName0_ from Users userentity0_ where userentity0_.firstName=? and userentity0_.lastName=?
When calling hibernateTemplate.find() I'm required to specify the table UserEntity whereas the log reports it's querying the table Users (as I specified with the #Table annotation).
Ideally I'd like to be consistent throughout my program and refer to the UserEntity table as Users rather than UserEntity. Is there some way I can do this? If so can I do it with HQL or would I need to write native SQL queries instead?
When you write HQL you are querying against the OO model. So in this case, your class name UserEntity is used. However, hibernate will translate this into a native SQL query and thus in the logs you will see references to users table. I'm not sure what your question is though. If the classname is UserEntity then throughout your application you should use UserEntity. I think that going into native SQL is only necessary when the HQL does not do what you want.
Vincent explained the matter, I'll just add some some clarifications.
The #Table annotation is optional, and merely indicates what the underlying table is (by default it is the same as the entity name (passing through a translation mechanism).
But the idea of hibernate (and orm layers) is to let the developer write code without any reference to the underlying relational model whatsoever. And that's what you should try to do - "forget" about the relational model beneath and use only the object model.

Categories