I'm trying to use JPA2 type-safe criteria queries with Hibernate 5.0.7.Final.
...
criteria.where( builder.equal( root.get(SingularAttribute.attr), value ));
//where parameters are
//criteria.where( builder.equal( root.get(Person_.name), "Can" ));
...
The root.get always throw NullPointerException.
The metamodel class Person_ for Person is generated by org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.
A similar problem was asked in JPA/Hibernate Static Metamodel Attributes not Populated -- NullPointerException but this time both classes are in the same package.
Stack trace:
java.lang.NullPointerException
at org.hibernate.jpa.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:123)
My code:
Interface that i use to make sure they will have getId();.
package it.unibz.db.hibernate.model;
public interface ModelInterface<PK extends Serializable> extends Serializable {
PK getId();
}
Model class
package it.unibz.db.hibernate.model;
#Entity
#Table(name ="person")
public class Person implements ModelInterface<Integer> {
#Id
private Integer id;
private String name;
public Integer getId() {
return id;
}
//other getter and setters
}
Generated metamodel Person_ class
package it.unibz.db.hibernate.model;
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(Person.class)
public abstract class Person_ {
public static volatile SingularAttribute<Person, String> name;
public static volatile SingularAttribute<Person, Integer> id;
}
Generic DAO class that i inherit with PersonDao
public class GenericDao<E extends ModelInterface<PK>, PK extends Serializable> implements DaoInterface<E, PK> {
private Class<E> type;
public GenericDao(Class<E> type) {
this.type = type;
//called as super(ClassName.class); eg. super(Person.class);
}
public List<E> readBy(SingularAttribute column, String value) throws Exception {
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<E> criteria = builder.createQuery(type);
Root<E> root = criteria.from(type);
criteria.select(root);
criteria.where( builder.equal( root.get(column), value ));
List<E> entityList = em.createQuery(criteria).getResultList();
em.close();
return entityList;
}
}
Some of my dependencies
hibernate-c3p0 5.0.7.Final
hibernate-entitymanager 5.0.7.Final
postgresql 9.4.1207.jre7
hibernate-jpamodelgen 5.0.7.Final
EDIT:
Running this code in the main method works
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
criteria.select(root);
criteria.where( builder.equal( root.get(Person_.name), "Can" ));
List<Person> entityList = em.createQuery(criteria).getResultList();
//do stuff with entityList
but the same code covered in a method throws NullPointerException.
public List<Person> readBy(SingularAttribute column, String value) throws Exception {
log.debug("Reading entity by");
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
criteria.select(root);
criteria.where( builder.equal( root.get(column), value ));
List<Person> entityList = em.createQuery(criteria).getResultList();
em.close();
return entityList;
}
So it seems that the problem is passing SingularAttribute parameter to the method readBy(SingularAttribute column, String value).
I tested this code in main and this prints false
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
System.out.println(root.get(Person_.name) == null); //false
meanwhile this throws InvocationTargetException caused by NullPointerException at root.get(column).
//invoked as personDao.test(Person_.name) from main
public void test(SingularAttribute column) {
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
System.out.println(root.get(column) == null); //InvocationTargetException
}
Is this what it's supposed to do? How can i pass SingularAttribute object to a method as a parameter?
Calling HibernateUtil.getEntityManager() in main before method call somehow works. It even works when i call literally a empty block of a method init().
It could be related with initialization of classes. Here's the code snippet.
public class HibernateUtil {
private static EntityManagerFactory emFactory;
private static EntityManager em;
private static final Logger log = LoggerFactory.getLogger(HibernateUtil.class);
private static final String PERSISTENCE_UNIT = "pt";
static{
log.info("Creating entity manager factory");
emFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
}
//calling this from main before PersonDao's method calls somehow works...
public void init(){} //does nothing
public static EntityManager getEntityManager(){
if(em != null && em.isOpen()){
closeEntityManager();
}
log.debug("Creating new entity manager");
em = emFactory.createEntityManager();
return em;
}
public static void close() throws Exception {
if(em != null && em.isOpen()){
closeEntityManager();
}
log.info("Closing entity manager factory");
emFactory.close();
}
private static void closeEntityManager(){
log.info("Closing last entity manager");
em.close();
}
}
Related
I'm using jquery Datatables together with Spring JPA.
I want to create a custom Query so that my Datatable will show a list of items based on the id of a ManyToOne related object.
PS. I have obviously declared Repositories, Mapper and Entities for these DTOs, I'm just avoiding to write all the classes because I find it useless.
public class SezioniDTO {
private static final long serialVersionUID = 1L;
private long id;
private LocalDate sezDtaggiornamento;
private Comune Comune;
}
public class Comune {
private static final long serialVersionUID = 1L;
private long id;
private String comCap;
private String comCodbelfiore;
private String comCodcomune;
}
These are my classes (i use mapstruct to map the dtos from the entities).
How can i use criteria builder inside my repository and services to search for Sezionis based on Comunes id?
I'm new to QueryDSL and Specifications, i just would like to obtain something like this:
#Query("Select * from Sezioni s WHERE s.id_Comune = :id", native="true")
public DataTablesOutput <Object> findByField (#Param(value="id", input);
This is the current Service Implementation
#Service
public class SezioniServiceImpl implements SezioniService{
#Autowired
SezioniRepository repo;
#Autowired
SezioniMapper mapper;
#Autowired
SezioniSpecifications sezSpec;
#Override
public List<SezioniDTO> findAll() {
return repo.findAll().stream().map(x -> mapper.entityToDto(x, new CycleAvoidingMappingContext()))
.collect(Collectors.toList());
}
#Override
public List<SezioniDTO> findByIdComune(Long idcom){
return repo.findSezionibyIdComune(idcom).stream().map(x -> mapper.entityToDto(x, new CycleAvoidingMappingContext()))
.collect(Collectors.toList());
}
#Override
public SezioniDTO save(SezioniDTO entity) {
return null;
}
#Override
public Optional<SezioniDTO> findById(Long id) {
// TODO Auto-generated method stub
return null;
}
#Override
public void delete(SezioniDTO entity) {
// TODO Auto-generated method stub
}
#Override
public void deleteById(Long id) {
// TODO Auto-generated method stub
}
#Override
public long count() {
// TODO Auto-generated method stub
return 0;
}
#Override
public DataTablesOutput<SezioniDTO> getSezioniTable(#Valid DataTablesInput input) {
return repo.findAll(input, null, null, a -> mapper.entityToDto(a, new CycleAvoidingMappingContext()) );
}
}
and the current Repository for SezioniDTO
#Repository
public interface SezioniRepository extends JpaRepository<Sezione,Long>, JpaSpecificationExecutor<Sezione>, DataTablesRepository<Sezione,Long> {
#Query(value = "SELECT * FROM db.sezione WHERE sez_com_prg = :id ORDER BY sez_numsezione", nativeQuery = true)
public List <Sezione> findSezionibyIdCom(#Param(value = "id") Long id);
}
Where Sezione is the current Entity. As you can see, it extends , and DataTablesOutput work only with Specifications, which I haven't understood at all.
I simply would like to create a method similar to the public List I have in the repo, but with a DataTablesOutput return instead.
Define Entities:
#Entity
public class Sezioni {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate sezDtaggiornamento;
#OneToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "comune_id")
private Comune Comune;
// getters & setter are omitted
}
and
#Entity
public class Comune {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String comCap;
private String comCodbelfiore;
private String comCodcomune;
// getters & setter are omitted
}
Define repository
#Repository
public interface SezioniRepository extends JpaRepository<Sezioni, Long> {
#Query("select s from Sezioni s where s.Comune.id = :id")
List<Sezioni> findByComuneId(Long id);
}
Use (here in test)
#DataJpaTest
class SezioniRepositoryTest {
#Autowired
SezioniRepository sezioniRepository;
#BeforeEach
void setUp() {
Comune comune = new Comune();
comune.setComCap("cap42");
comune.setComCodcomune("cod43");
Sezioni sezioni = new Sezioni();
sezioni.setComune(comune);
sezioni.setSezDtaggiornamento(LocalDate.of(1970, 1, 1));
sezioniRepository.save(sezioni);
}
#Test
void test() {
List<Sezioni> sezionis = sezioniRepository.findByComuneId(1L);
assertEquals(1, sezionis.size());
assertEquals("cap42",sezionis.get(0).getComune().getComCap());
}
}
Next you can use MapStruct to map entities into DTO (if you prefer to expose DTO on your API)
Criteria Builder's advantage is to build queries dynamically upon your business login needs:
Consider next example:
#Service
public class SezioniQuery {
#PersistenceContext
private EntityManager entityManager;
List<Sezioni> select(TriFunction<CriteriaBuilder, Root<Sezioni>, CriteriaQuery<Sezioni>, CriteriaQuery<Sezioni>> builder) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Sezioni> query = criteriaBuilder.createQuery(Sezioni.class);
// SQL FROM clause
Root<Sezioni> from = query.from(Sezioni.class);
// SQL SELECT clause
CriteriaQuery<Sezioni> select = query.select(from);
// build WHERE somewhere later
CriteriaQuery<Sezioni> apply = builder.apply(criteriaBuilder, from, query);
// execute
TypedQuery<Sezioni> typedQuery = entityManager.createQuery(apply);
return typedQuery.getResultList();
}
}
^^ here we define boilerplate.
Next we can reuse it to build different queires:
// #BeforeEach void setUp() {...} omitted see prev. answer
#Test
void testEqual() {
Long id = 1L;
List<Sezioni> sezionis = sezioniQuery.select((cb, from, query) ->
// WHERE id=1
query.where(cb.equal(from.get("id"), id)));
assertEquals(1, sezionis.size());
assertEquals("cap42",sezionis.get(0).getComune().getComCap());
}
#Test
void testGreater() {
List<Sezioni> sezionis = sezioniQuery.select((cb, from, query) ->
// WHERE id > 0
query.where(cb.gt(from.get("id"), 0)));
assertEquals(1, sezionis.size());
assertEquals("cap42",sezionis.get(0).getComune().getComCap());
}
So, using CriteriaBuilder you can build queries dynamically but this requires a bit more code, non-type-safe code.
Whereas JpaRepository extension is type-safe but non-dynamiŃ
I'm trying to use Criteria Api for for making queries on database. I found this article:
http://docs.oracle.com/javaee/6/tutorial/doc/gjivm.html
The problem is this code :
Root<Pet> pet = cq.from(Pet_);
I can't import Pet_ class. Do i need to create that class or?
This is my code:
public class DnevnikFacade extends AbstractFacade<Dnevnik> {
#PersistenceContext(unitName = "zadaca_4_1PU")
private EntityManager em;
CriteriaQuery criteriaQuery;
CriteriaBuilder criteriaBuilder;
private Root <Dnevnik> dnevnik ;
private List<Predicate> filteri;
#Override
protected EntityManager getEntityManager() {
criteriaBuilder = em.getCriteriaBuilder();
criteriaQuery = criteriaBuilder.createQuery();
dnevnik = criteriaQuery.from(Dnevnik.class);
return em;
}
public DnevnikFacade() {
super(Dnevnik.class);
}
public List<Dnevnik> dohvatiDnevnikPremaFilterima(){
criteriaQuery.select(dnevnik).where(filteri.toArray(new Predicate[]{}));
return em.createQuery(criteriaQuery).getResultList();
}
public void filterStatus(String status){
filteri.add(criteriaBuilder.equal(dnevnik.get(Dnevnik_.status), status));
}
}
And that Dnevnik_status is the problem. Status is a column in table Dnevnik. What am i doing wrong, can somebody help me?
what does that class_ mean? How can i resolve it? Thanks.
i'm testing my web-app with junit and mockito (for business layer).
i have an entity:
#Entity
#Table(name = "brand")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Brand.findAll", query = "SELECT b FROM Brand b"),
#NamedQuery(name = "Brand.findByOid", query = "SELECT b FROM Brand b WHERE b.oid = :oid"),
#NamedQuery(name = "Brand.findByName", query = "SELECT b FROM Brand b WHERE b.name = :name")})
public class Brand implements Serializable {
...
and a session bean
#Stateless
public class BrandFacade extends AbstractFacade<Brand> {
#PersistenceContext(unitName = "MyWheelJSFPU")
private EntityManager em;
public void setEm(EntityManager em) {
this.em = em;
}
...
#Override
public List<Brand> findAll(){
return em.createNamedQuery("Brand.findAll", Brand.class).getResultList();
}
...
now i want to test .findAll
public class BrandFacadeTest {
#Mock
private EntityManager mockedEntityManager;
#Mock
private TypedQuery mockedQuery;
private BrandFacade brandFacade;
public BrandFacadeTest() {
}
#BeforeClass
public static void setUpClass() {
System.out.println("Start BrandFacadeTest");
}
#AfterClass
public static void tearDownClass() {
}
#Before
public void initDependencies() {
brandFacade=new BrandFacade();
brandFacade.setEm(mockedEntityManager);
System.out.println("mockEmCreated");
}
/**
* Test of findAll method, of class BrandFacade.
*/
#Test
public void testFindAll() {
System.out.println("findAll");
List<Brand> brands=new ArrayList<>();
when(mockedEntityManager.createNamedQuery("Brand.findAll", Brand.class)).thenReturn(mockedQuery);
when(mockedQuery.getResultList()).thenReturn(brands);
int initNumber=brandFacade.findAll().size();
//creating Brand
Brand b1 = new Brand(1, "mo");
brandFacade.create(b1);
verify(mockedEntityManager, times(1)).persist(any());
brands.add(b1);
assertEquals("error",initNumber+1, brandFacade.findAll().size());
}
...
at this line
when(mockedEntityManager.createNamedQuery("Brand.findAll", Brand.class)).thenReturn(mockedQuery);
it returns a java.lang.nullpointerexception...why??? what's the problem?
i made exactly the same for another entity and it work!
If you want to use the #Mock annotation, you must run the unittest either with MockitoJUnitRunner, or set the following in your test case #Before clause:
MockitoAnnotations.initMocks(BrandFacadeTest);
See here: http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Mockito.html#mock_annotation
I am trying to use FullTextEntityManager (and Spring) but getting a 'Session is closed' exception. I am able to query fine the first time, but the 2nd time, the exception is thrown. Here's my config:
#Service
#Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public class SearchServiceImpl extends BaseService implements SearchService {
public List<StrainSearchResultsListItem> advancedSearch(Pageable page,String species) {
return searchRepository.advancedSearch(page, species);
}
Repo impl:
#Repository
#Transactional(readOnly = true)
public class SearchRepositoryImpl implements SearchRepository {
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected FullTextEntityManager getFullTextEntityManager() {
if (fullTextEntityManager == null) {
fullTextEntityManager = Search.getFullTextEntityManager(getEntityManager());
}
return fullTextEntityManager;
}
As soon as I call fullTestQuery.getResultList() the second time, it hurls with a 'Session is closed' exception.
FullTextQuery fullTextQuery =
getFullTextEntityManager()
.createFullTextQuery(booleanQuery, Strain.class);
fullTextQuery.getResultList()
Any ideas are appreciated.
thanks
It might be that you forgot to enable TransactionManagement in your spring configuration file. #EnableTransactionManagement to a spring configuration file to enable transaction management.
Your entity class should be like this-
#Entity
#Table(name="keywordsentity")
#Indexed
#AnalyzerDef(
name="fulltext",
tokenizer=#TokenizerDef(factory=StandardTokenizerFactory.class),
filters={
#TokenFilterDef(factory=LowerCaseFilterFactory.class),
#TokenFilterDef(factory=SnowballPorterFilterFactory.class,
params={#Parameter(name="language", value="English") })
}
)
public class Keywordsentity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#JsonProperty
//index = Index.YES, analyze=Analyze.YES, store = Store.YES
#Field
#Analyzer(definition="fulltext")
private String keywordname;
And Your service class should be like this
#Service
public class KeywordService {
#PersistenceContext(type = PersistenceContextType.EXTENDED, name = "keywordPU")
private EntityManager em;
private FullTextEntityManager ftem;
public void updateFullTextIndex() throws Exception {
getFullTextEntityManager().createIndexer().startAndWait();
}
protected FullTextEntityManager getFullTextEntityManager() {
if (ftem == null) {
ftem = Search.getFullTextEntityManager(em);
}
return ftem;
}
#Transactional
public List<Keywordsentity> search(String summary, String description)
{
String searchString = summary.concat(" ").concat(description);
System.out.println("searchString-----------------------------"+searchString);
QueryBuilder qb = getFullTextEntityManager().getSearchFactory().buildQueryBuilder().forEntity(Keywordsentity.class).get();
//lucene query
org.apache.lucene.search.Query query = qb
.keyword()
.onField("keywordname").matching(searchString)
.createQuery();
Query fullTextQuery = getFullTextEntityManager().createFullTextQuery(query, Keywordsentity.class);
System.out.println("fullTextQuery------------------================="+fullTextQuery);
List<Keywordsentity> result = new ArrayList<Keywordsentity>();
try
{
result = fullTextQuery.getResultList();
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("size --------------------=========="+result.size());
for (Keywordsentity keywordone : result) {
System.out.println("keyword------------"+keywordone);
Map<String,String> team =new HashMap<String,String>();
Set<Teamsentity> teams= keywordone.getTeamsentity();
{
for(Teamsentity teamsentityone :teams )
{
String ids = String.valueOf(teamsentityone.getId());
team.put("id",ids);
team.put("name",teamsentityone.getName());
team.put("description",teamsentityone.getDescription());
}
System.out.println("teams =================="+teams);
}
}
return result;
}
}
Then Repository and controller should be normal way nothing else.
In dependency only one -
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>5.10.5.Final</version>
</dependency>
I'm using SqlResultSetMapping and the Entity annotations (SqlResultSetMapping requires an Entity with an Id) to tell Hibernate how to populate instances of Foo with native query results data.
Non-persisted entity:
#SqlResultSetMapping(name = "fooMapping", entities = #EntityResult(entityClass = Foo.class))
#Entity
public class Foo {
#Id
public Long row_id;
public String name;
}
Native query:
String sql = "SELECT id AS row_id, friendlyName AS name FROM SomeTable";
Query q = JPA.em().createNativeQuery(sql, "fooMapping");
List<Foo> fooList = q.getResultList();
The problem is, a table called "Foo" gets created automatically for me (using Play! Framework in dev mode), but Foo is not a model and should not be persisted.
How do I instruct hibernate not to create this table?
Using #ConstructorResult will work great once it's available for your persistence layer. Until then, there is a Hibernate-specific approach using an org.hibernate.SQLQuery and an org.hibernate.transform.ResultTransformer that does not depend on #SqlResultSetMapping. Because a POJO is populated, Hibernate finds no #Entity to automatically turn into a table.
Non-persisted POJO:
public class Foo {
public Long row_id;
public String name;
}
ResultTransformer:
public static class FooResultTransformer implements ResultTransformer {
#Override
public List transformList(List list) { return list; }
#Override
public Object transformTuple(Object[] tuple, String[] aliases) {
List<String> aliasList = Arrays.asList(aliases);
Foo foo = new Foo();
foo.row_id = ((Number) getValue(tuple, aliasList, "row_id", 0L))
.longValue();
foo.name = (String) getValue(tuple, aliasList, "name", null);
return foo;
}
private static Object getValue(Object[] tuple, List<String> aliases,
String field, Object defaultValue)
{
// unchecked for berevity
if (tuple[aliases.indexOf(field)] == null) {
return defaultValue;
}
return tuple[aliases.indexOf(field)];
}
}
Native SQLQuery:
String sql = "SELECT id AS row_id, friendlyName AS name FROM SomeTable";
Session session = JPA.em().unwrap(Session.class);
SQLQuery q = session.createSQLQuery(sql);
q.setResultTransformer( new FooResultTransformer() );
List<Foo> fooList = q.list();
Unfortunately this isn't easy...
If you are using JPA 2.1 support for #ConstructorResult (seems there's only support in hibernate 4.3.0.Beta2 so you might not be using), you can use #ConstructorResult as follows:
#SqlResultSetMapping(name="fooMapping",
classes={
#ConstructorResult(targetClass=Foo.class, columns={
#ColumnResult(name="row_id", type=Integer.class),
#ColumnResult(name="name", type=String.class)
})
}
)
public class Foo {
public Long row_id;
public String name;
public Foo(Long rowId, String name) {
...
}
}