Adding a single projection to a criteria query - java

I am new to hibernate and am struggling with adding a single projection to a criteria query. I am getting an error with the following code: "java.lang.Integer cannot be cast to [Ljava.lang.Object, on line 29. I know it is something very simple, but I cant figure out what I am doing wrong here!
Code is as follows:
package com.simpleprogrammer;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import java.util.Date;
import java.util.List;
import java.util.Objects;
public class Program {
public static void main(String[] args) {
System.out.println(org.hibernate.Version.getVersionString());
System.out.println("Creating session!");
PopulateSampleData();
Session session = HibernateUtilities.getSessionFactory().openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name", "Joe")).setProjection(Projections.property("id"));
List<Object[]> results = criteria.list();
for(Object[] result : results) {
for (Object o : result)
System.out.println("Name is " + o.toString());
}
session.close();
HibernateUtilities.getSessionFactory().close();
}
private static void PopulateSampleData() {
Session session = HibernateUtilities.getSessionFactory().openSession();
session.beginTransaction();
User joe = CreateUser("Joe", 500, 50, "Good job", "You made it!");
session.save(joe);
User bob = CreateUser("Bob", 300, 20, "Taco time!");
session.save(bob);
User amy = CreateUser("Amy", 250, 200, "Yes!!!");
session.save(amy);
session.getTransaction().commit();
session.close();
}
private static User CreateUser(String name, int goal, int total, String... alerts) {
User user = new User();
user.setName(name);
user.getProtienData().setGoal(goal);
user.addHistory(new UserHistory(new Date(), "Set goal to " + goal));
user.getProtienData().setTotal(total);
user.addHistory(new UserHistory(new Date(), "Set total to " + total));
for (String alert : alerts) {
user.getGoalAlerts().add(new GoalAlert(alert));
}
return user;
}
}

I suspect that criteria.list() is returning List<Integer> instead of List<Object[]> since a single column is fetched.
Try changing
List<Object[]> results = criteria.list();
to
List<Integer> results = criteria.list();

Related

I'm getting error in particular line....what should I change?

This is the line where I'm getting the error
List<Map<String, Object>> users = jdbcTemplate.queryForList("select * from user where email=? and pass=?",new Object[] { email, pass }, new MyRowMapper());
This is the whole code:
package com.example.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.example.model.User;
#Repository
public class UserDao {
#Autowired
private JdbcTemplate jdbcTemplate;
public int insert(User user) {
return jdbcTemplate.update("insert into user values(?,?,?,?,?)",
new Object[] { user.getName(), user.getEmail(), user.getPass(),user.getProfileimage(),user.getExpensetable() });
}
public int updateProfile(User user) {
return jdbcTemplate.update("update user set name=?,pass=?,profile=?,expensetable=? where email=?",
new Object[] { user.getName(), user.getPass(), user.getProfileimage(),user.getExpensetable(), user.getEmail() });
}
public User login(String email, String pass) {
User user = null;
List<Map<String, Object>> users = jdbcTemplate.queryForList("select * from user where email=? and pass=?",new Object[] { email, pass }, new MyRowMapper());
if (users.size() > 0) {
user = (User) users.get(0);
}
return user;
}
private class MyRowMapper implements RowMapper<User> {
#Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setName(rs.getString(1));
user.setEmail(rs.getString(2));
user.setPass(rs.getString(3));
user.setProfileimage(rs.getString(4));
user.setExpensetable(rs.getString(5));
return user;
}
}
}
This is the error:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/ExpenseSpringProject] threw exception [Request processing failed; nested exception is org.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [select * from user where email=? and pass=?]; Invalid argument value: java.io.NotSerializableException; nested exception is java.sql.SQLException: Invalid argument value: java.io.NotSerializableException] with root cause
java.io.NotSerializableException: com.example.dao.UserDao$MyRowMapper
You are calling the wrong JdbcTemplate method.
The method you are calling takes a query and a varargs array of the bind parameter values. The way you are calling it, you are passing the following as bind parameter values:
an array containing your email and password.
a row-mapper.
The row-mapper is not being used to map rows, instead you are attempting to pass it to the database as if it is a value itself.
I think you want to use the overload of JdbcTemplate.query that takes a query, a row-mapper and the bind parameter values in that order.
Try replacing the line
List<Map<String, Object>> users = jdbcTemplate.queryForList("select * from user where email=? and pass=?",new Object[] { email, pass }, new MyRowMapper());
with
List<User> users = jdbcTemplate.query("select * from user where email=? and pass=?", new MyRowMapper(), email, pass);
Once you've done that, the cast to User in the line user = (User) users.get(0); should become unnecessary and you can remove it.

java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement cannot be cast to java.sql.ResultSet

Hello I keep getting this error while using API URL to get specific parking spot number list of reservations, this is the error:
java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement cannot be cast to java.sql.ResultSet
here is my method that sends a query for specific parking space ID:
public List<Book> getSpecBook(int id) throws Exception {
List<Book> books = new ArrayList<>();
//int idInt = Integer.parseInt(id);
Connection myConn = null;
PreparedStatement myStmt = null;
ResultSet myRs = null;
try {
myConn = dataSource.getConnection();
// create sql statement
String sql = "SELECT * FROM `rezerwacje_miejsc` WHERE `NR_MIEJSCA`=?";
myStmt = myConn.prepareStatement(sql);
myStmt.setInt(1, id);
myRs = myStmt.executeQuery();
while (myRs.next()) {
// retrive data from result set row
int placeNo = ((ResultSet) myStmt).getInt("NR_MIEJSCA");
Date start = ((ResultSet) myStmt).getDate("START");
Date end = ((ResultSet) myStmt).getDate("KONIEC");
String userName = ((ResultSet) myStmt).getString("IMIE_NAZWISKO");
int phone = ((ResultSet) myStmt).getInt("TELEFON");
// create new temporary Book object
Book tempBook = new Book(placeNo, start, end, userName, phone);
// add it to our list of Books
books.add(tempBook);
}
return books;
} finally {
// clean up JDBC objects
close(myConn, myStmt, myRs);
}
}
and here is my API class:
package com.pbs.web.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pbs.web.jdbc.ParkingBookSystem.Book;
import com.pbs.web.jdbc.ParkingBookSystem.BookDbUtil;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
#Path("books")
#Produces(MediaType.APPLICATION_JSON)
public class BookingRestController {
private BookDbUtil bookDbUtil = new BookDbUtil();
#GET
#Path("/")
public Response getAllBooks() throws Exception {
List<Book> books = bookDbUtil.getBooks();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(books);
return Response.ok().entity(json).build();
}
#GET
#Path("/{id}")
public Response getSpecBook(#PathParam("id") int id) throws Exception {
List<Book> books = bookDbUtil.getSpecBook(id);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(books);
return Response.ok().entity(json).build();
}
}
I'm not able to find the issue.
You're writing lines like
int placeNo = ((ResultSet) myStmt).getInt("NR_MIEJSCA");
This is evidently where you are getting the error. The error says that a statement cannot be cast to a result set, and here you are trying to cast a statement to a result set.
I cannot fathom why you would think you'd access the result set this way, especially given that you've already done the work to get the result set from the statement. It's in your variable myRs.
You probably want
int placeNo = myRs.getInt("NR_MIEJSCA");
(and similar for other lines) instead.

Hibernate SessionFactory - correct way to create factory, session and handle resources

For teaching purposes, I am creating Hibernate console applications. Since Hibernate is quite complex, I want to be sure that I handle the initialization, exceptions, and shutdown correctly. The examples that I have found are not optimal in my opinion. (Official Hibernate examples use test cases.)
I have HibernateUtil for initialization and shutdown of Hibernate.
package com.zetcode.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class HibernateUtil {
private SessionFactory sessionFactory;
public HibernateUtil() {
createSessionFactory();
}
private void createSessionFactory() {
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure() // configures settings from hibernate.cfg.xml
.build();
sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
// try {
// sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
// } catch (Exception e) {
// The registry would be destroyed by the SessionFactory, //but we had trouble building the SessionFactory
// so destroy it manually.
// StandardServiceRegistryBuilder.destroy(registry);
}
}
public SessionFactory getSessionFactory() {
// if (sessionFactory == null) {
// createSessionFactory();
// }
return sessionFactory;
}
public void shutdown() {
getSessionFactory().close();
}
}
Here is a console Java application:
package com.zetcode.main;
import com.zetcode.bean.Continent;
import com.zetcode.bean.Country;
import com.zetcode.util.HibernateUtil;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class Application {
public static void main(String[] args) {
HibernateUtil hutil = new HibernateUtil();
SessionFactory sessionFactory = hutil.getSessionFactory();
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
Continent europe = new Continent("Europe");
Continent asia = new Continent("Asia");
Country svk = new Country("Slovakia");
Country hun = new Country("Hungary");
Set<Country> europeCountries = new HashSet<>();
europeCountries.add(svk);
europeCountries.add(hun);
europe.setCountries(europeCountries);
Country chi = new Country("China");
Country afg = new Country("Afganistan");
Set<Country> asiaCountries = new HashSet<>();
asiaCountries.add(chi);
asiaCountries.add(afg);
asia.setCountries(asiaCountries);
session.save(europe);
session.save(asia);
// moved
//session.getTransaction().commit();
Query query = session.createQuery("SELECT c FROM Country c");
List<Country> countries = query.getResultList();
countries.stream().forEach((x) -> System.out.println(x));
Query query2 = session.createQuery("SELECT c FROM Continent c");
List<Continent> continents = query2.getResultList();
continents.stream().forEach((x) -> System.out.println(x));
session.getTransaction().commit();
} finally {
hutil.shutdown();
}
}
}
The example works OK. But, is this code correct? I am using Hibernate 5.2.
Edit I have incorporated the suggestions from the comments into the code.

Several issues while trying to write the same code from another project

The teacher from my Java-coding class has published on his web page an example of what he expects us to code for ourselves. When I tried to recreate the same code within my own lab, however, I have been facing several errors. Here is the code:
public class StudentRepositoryImpl extends Repository<Student, Long> implements StudentRepositoryCustom {
private static final Logger log = LoggerFactory.getLogger(StudentRepositoryImpl.class);
public StudentRepositoryImpl()
{
super(Student.class);
}
#Override
#Transactional
public List<Student> findAllWithLabsSqlQuery()
{
log.trace("findAllWithLabsSqlQuery: method entered");
HibernateEntityManager hibernateEntityManager = getEntityManager().unwrap(HibernateEntityManager.class);
Session session = hibernateEntityManager.getSession();
Query query = session.createSQLQuery("select distinct {s.*}, {sd.*}, {d.*}" +
" from student s" +
" left join student_lab sd on sd.student_id = s.id" +
" left join lab d on d.id = sd.lab_id")
.addEntity("s", Student.class)
.addJoin("sd", "s.studentLabs")
.addJoin("d", "sd.lab")
.addEntity("s", Student.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<Student> students = query.list();
log.trace("findAllWithLabsSqlQuery: students={}", students);
return students;
}
#Override
#Transactional
public List<Student> findAllWithLabsJpql() {
log.trace("findAllWithLabsJpql: method entered");
javax.persistence.Query query = getEntityManager().createQuery("select distinct s from Student s" +
" left join fetch s.studentLabs sd" +
" left join fetch sd.lab d");
List<Student> students = query.getResultList();
log.trace("findAllWithLabsJpql: students={}", students);
return students;
}
#Override
#Transactional
public List<Student> findAllWithLabsJpaCriteria() {
log.trace("findAllWithLabsJpaCriteria: method entered");
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Student> query = criteriaBuilder.createQuery(Student.class);
query.distinct(Boolean.TRUE);
Root<Student> from = query.from(Student.class);
Fetch<Student, StudentLab> studentLabFetch = from.fetch(Student_.studentLabs, JoinType.LEFT);
studentLabFetch.fetch(StudentLab_.discipline, JoinType.LEFT);
List<Student> students = getEntityManager().createQuery(query).getResultList();
log.trace("findAllWithLabsJpaCriteria: students={}", students);
return students;
}
}
The errors I am facing are:
1 - the super method ("Cannot resolve method 'super(java.lang.Class)'")
2 - every getEntityManager function ("Cannot resolve method 'getEntityManager'")
3 - the "Student_" and "StudentLab_" ("Cannot resolve symbol")
In his project the same code, albeit with class name modifications, works. Is it something to do with the .iml or pom.xml files?
Here are the imported libraries:
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.jpa.HibernateEntityManager;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.*;
import java.util.List;
import ro.ubb.books.core.model.*;
import ro.ubb.books.core.repository.*;
If you have also copied pom.xml, try running following command.
mvn clean package
Note : mvn(maven) must be installed.

Why does Hibernate transaction not update my database?

I'm having an issue with my login class. If a user unsuccessfully attempts to login with a username then that user account should be disabled. At runtime there are no errors but nothing changes in my database. Am I doing something wrong with updating my database through Hibernate, I thought I could just use my UserBean.class to access properties, change them and then commit the Hibernate transaction?
Here is my LoginDAO.class:
package com.sga.app.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.criterion.Restrictions;
import org.owasp.encoder.Encode;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import com.sga.app.beans.UserBean;
import com.sga.app.hibernate.HibernateUtil;
import com.sga.app.security.LoginFailureEventListener;
import com.sga.app.security.XssRequestWrapper;
#Component("loginDAO")
#Transactional
#Configuration
public class LoginDAO implements
ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
private int loginAttemptsThreshold;
private int failedLoginAttempts;
private static Logger logger = Logger
.getLogger(LoginFailureEventListener.class);
private static Session session;
private Criteria criteria;
private String username;
private boolean enabled;
private String forename;
private String authority;
private XssRequestWrapper xssReqWrapper;
private PreparedStatement prepStmtUsers;
private PreparedStatement prepStmtAuthorities;
private String URL = "jdbc:oracle:thin:system/sgaWebApp#localhost:1521/XE";
private String updateUsersStatement = "insert into users (username, password)
values (:username, :password)";
private String updateAuthoritiesStatement = "insert into authorities (username,
authority) values (:username, :authority)";
#Bean
public LoginDAO loginDAO() {
return new LoginDAO();
}
public void setLoginAttemptsThreshold(int threshold) {
this.loginAttemptsThreshold = threshold;
}
#Transactional
public void loginUser(UserBean user, BindingResult result) {
try {
Connection conn = DriverManager.getConnection(URL);
// clean out any possible XSS injection
String cleanUsernameValueInput = cleanOutXSSVulnerabilities("j_username");
String cleanPasswordValueInput = cleanOutXSSVulnerabilities("j_password");
// OWASP encoding
String safeUsername = Encode.forHtml(cleanUsernameValueInput);
prepStmtUsers.setString(1, safeUsername);
String safePassword = Encode.forHtml(cleanPasswordValueInput);
prepStmtUsers.setString(2, safePassword);
prepStmtAuthorities.setString(1, safeUsername);
String safeUserAuthority = Encode.forHtml(user.getAuthority());
prepStmtAuthorities.setString(2, safeUserAuthority);
// execute login process
prepStmtUsers = conn.prepareStatement(updateUsersStatement);
prepStmtAuthorities = conn
.prepareStatement(updateAuthoritiesStatement);
prepStmtUsers.executeUpdate();
prepStmtAuthorities.executeUpdate();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (AccessDeniedException accessDenied) {
accessDenied.printStackTrace();
}
}
private String cleanOutXSSVulnerabilities(String input) {
return xssReqWrapper.cleanXSS(input);
}
#Override
public void onApplicationEvent(
AuthenticationFailureBadCredentialsEvent event) {
if (event.getException().getClass()
.equals(UsernameNotFoundException.class)) {
return;
}
// print registration attempts to log file for security investigation if
// required
logger.info("Registration attempt failed: " + event.getException());
logger.info("Registration attempt number: " + event.getTimestamp());
String userId = event.getAuthentication().getName();
logger.info("FAILED LOGIN ATTEMPT NUMBER "
+ recordLoginAttempts(userId));
recordLoginAttempts(userId);
if (recordLoginAttempts(userId) >= loginAttemptsThreshold) {
lockoutUser(userId);
}
}
private int recordLoginAttempts(String userId) {
failedLoginAttempts++;
return failedLoginAttempts;
}
#SuppressWarnings("unchecked")
private ArrayList<UserBean> getUserAccountDetails(String input) {
ArrayList<UserBean> returnValues = new ArrayList<UserBean>();
session = HibernateUtil.createSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
session.beginTransaction();
criteria = session.createCriteria(UserBean.class);
List<UserBean> retrievedUser = criteria.add(
Restrictions.like("username", input)).list();
for (UserBean userDetails : retrievedUser) {
logger.debug("USERNAME INSIDE THE GET USER ACCOUNT DETAILS METHOD: "
+ userDetails.getUsername());
logger.debug("AUTHORITY INSIDE THE GET USER ACCOUNT DETAILS METHOD: "
+ userDetails.getAuthority());
returnValues.add(userDetails);
}
session.flush();
session.getTransaction().commit();
session.close();
return returnValues;
}
private void lockoutUser(String userId) {
ArrayList<UserBean> userAccountValues = getUserAccountDetails(userId);
session = HibernateUtil.createSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
session.beginTransaction();
for (UserBean user : userAccountValues) {
username = user.getUsername();
forename = user.getForename();
enabled = user.getEnabled();
authority = user.getAuthority();
logger.debug("USERNAME: " + username);
logger.debug("FORENAME: " + forename);
logger.debug("ENABLED BEFORE CHANGE: " + enabled);
user.setEnabled(false);
logger.debug("AUTHORITY BEFORE CHANGE: " + authority);
user.setAuthority("BLOCKED");
}
session.flush();
session.getTransaction().commit();
logger.debug("ENABLED AFTER CHANGE: " + enabled);
logger.debug("AUTHORITY AFTER CHANGE: " + authority);
session.close();
ManagedSessionContext.unbind(HibernateUtil.createSessionFactory());
}
}
I don't think you should be invoking openSession in that manner. I would highly suggest you rewrite the method to not do any "session" related work at all. Let Spring handle it, especially since you are already using #Transactional.
Either way, in the lockoutUser() method, the users you find, aren't bound to the session that gets created after it.
ArrayList<UserBean> userAccountValues = getUserAccountDetails(userId);
session = HibernateUtil.createSessionFactory().openSession();
So, later in the method when you update the user instances of that ArrrayList, the session doesn't realize that the user instances are to be persisted because the session was never tracking them.
Try to have only one session per thread. Each method can have its own transaction, but we rarely come across situations where we need more than one session in a thread. This doesn't seem to be that kind of a situation.
session.flush();
session.getTransaction().commit();
session.close();
Try to delete session.flush(); or put it after session.getTransaction().commit(); may work.
It doesn't appear that you call session.save(Object) or session.update(Object).

Categories