Defining JPA repositories in test - java

I created some library with aspect which works with JPA repositories. What I am trying to achieve is to create tests for that particular aspect. There are neither repositories nor entities in source code of the library. So in test I need to test this aspect inside of spring context with test entities and repositories. So in test sources I defined DataJpaTest with properties to enable in-memory h2 and jpa ddl create, an entity class and repository interface which derives from CrudRepository. By starting of test I see JPA saying after scanning that 0 repositories found.
I have tried to add repository class into context configuration annotation, then in enable JPA repositories, used also entity scan. Nothing works and I understand that what can be is that probably either repositories and entities scan generally disabled in test classes or there is some kind of other trick which I do not know yet. Does enybody tackled already such a problem?

have you mentioned the annotations in their respective places?
like this
entity class
#Entity
#Table(name = "demoEntity")
public class DemoEntity{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
//attributes
//methods / getters & setters
}
then repository
#Repository
public interface DemoEntityRepository extends JpaRepository<DemoEntity, Intiger>{
}
hopefully, then it should work else you can ping me any time, I'm always here.
and please provide some sample code or error pages for better understanding.

Related

filter Data in Spring Boot Data REST

I use Spring Boot Data REST, yes, I write something like below:
#RepositoryRestResource
public interface ExerciseRepository extends JpaRepository<Exercise, Integer> {}
then I open 127.0.0.1/exercises. It will show all exercises.
But I want only show some appointed exercises(eg. exercise id < 100, or other complicated logic) on the 127.0.0.1/exercises.
I know I can use #RestController, but how can I do this with Spring Boot Data REST?
#RepositoryRestResource(path="exercises",collectionResourceRel = "exercises")
can you edit this according to your own code ? I think this will work for you
You can declare an interface method, for example:
#RepositoryRestResource
public interface ExerciseRepository extends JpaRepository<Exercise, Integer> {
List<Exercise> findByIdLessThan(#Param("id") Integer id);
}
In this case, the query is derived from the method name directly, but you can also write a query manually using #Query, for more details check the documentation.
To invoke the method use the following API request:
GET http://localhost:8080/exercises/search/findByIdLessThan?id=100
For reference, Spring Data REST - Useful notes.
EDIT:
If you use Hibernate as your persistence provider, you can use #Where for static filtering, and #Filter for dynamic filtering where filters are defined and configured at runtime, according to Hibernate User Guide.
For example, you can annotate the entity with #Where and define a condition that will be applied to all queries related to that entity:
#Where(clause = "id<100")
#Entity
public class Exercise{
//...
}

Dynamic schema in Hibernate #Table Annotation

Imagine you have four MySQL database schemas across two environments:
foo (the prod db),
bar (the in-progress restructuring of the foo db),
foo_beta (the test db),
and bar_beta (the test db for new structures).
Further, imagine you have a Spring Boot app with Hibernate annotations on the entities, like so:
#Table(name="customer", schema="bar")
public class Customer { ... }
#Table(name="customer", schema="foo")
public class LegacyCustomer { ... }
When developing locally it's no problem. You mimic the production database table names in your local environment. But then you try to demo functionality before it goes live and want to upload it to the server. You start another instance of the app on another port and realize this copy needs to point to "foo_beta" and "bar_beta", not "foo" and "bar"! What to do!
Were you using only one schema in your app, you could've left off the schema all-together and specified hibernate.default_schema, but... you're using two. So that's out.
Spring EL--e.g. #Table(name="customer", schema="${myApp.schemaName}") isn't an option--(with even some snooty "no-one needs this" comments), so if dynamically defining schemas is absurd, what does one do? Other than, you know, not getting into this ridiculous scenario in the first place.
I have fixed such kind of problem by adding support for my own schema annotation to Hibernate. It is not very hard to implement by extending LocalSessionFactoryBean (or AnnotationSessionFactoryBean for Hibernate 3). The annotation looks like this
#Target(TYPE)
#Retention(RUNTIME)
public #interface Schema {
String alias() default "";
String group() default "";
}
Example of using
#Entity
#Table
#Schema(alias = "em", group = "ref")
public class SomePersistent {
}
And a schema name for every combination of alias and group is specified in a spring configuration.
you can try with interceptors
public class CustomInterceptor extends EmptyInterceptor {
#Override
public String onPrepareStatement(String sql) {
String prepedStatement = super.onPrepareStatement(sql);
prepedStatement = prepedStatement.replaceAll("schema", "Schema1");
return prepedStatement;
}
}
add this interceptor in session object as
Session session = sessionFactory.withOptions().interceptor(new MyInterceptor()).openSession();
so what happens is when ever onPrepareStatement is executed this block of code will be called and schema name will be changed from schema to schema1.
You can override the settings you declare in the annotations using a orm.xml file. Configure maven or whatever you use to generate your deployable build artifacts to create that override file for the test environment.

Share class with annotations

I want to use a simple class with hibernate annotations in a non db project.
I dont wanna dublicate the code and remove annotations.
Is there a way for doing this like using annotations in subclass for parent class's attributes. So i can share the parent class.
Any help would be great, thanks.
Edit:
For example: I have a class:
#Entity
#Table(name = "Sample")
Class Sample{
#Column(name = "attr1")
private String attr1;
// getter setters etc.
}
This class works good for a java project with db dependencies set.
But I serve a restful service with this class.
My client app do not need any db related functions so I dont include any db related jars.
So this is my problem I want to use same classes since both are common for two projects. But I do not need db jars which leads to #Entity annotations to compile errors.
If there is some way to do this, I would be very happy.
Thanks alot.
use hibernate validation groups
Basic Validation Example
create 2 validation groups and use one of them for db project and other for not db project

Spring Data MongoDB Cross-Store plugin and JPA PrePersist and PreUpdate

We have an application with the following set up:
Java 6.0
Spring Data JPA 1.1.0.RELEASE
Spring Data MongoDB 1.0.2.RELEASE
Spring Data MongoDB Cross-Store 1.0.2.RELEASE
Hibernate JPA 2.0
We have several classes in this application that use the JPA PrePersist, PreUpdate, PostPersist and PostUpdate annotations. An example is given below.
#Entity
public class Person
{
private String password;
#PrePersist
#PreUpdate
public void beforeSave()
{
if(!Security.isEncrypted(this.password))
{
this.password = Security.encrypt(this.password);
}
}
}
As soon as we turn on AspectJ weaving for the cross-store plugin, the Spring application context fails to load with the error:
Caused by: javax.persistence.PersistenceException: You can only annotate one callback method with javax.persistence.PrePersist in bean class: org.example.domain.Person
at org.hibernate.ejb.event.CallbackResolver.resolveCallback(CallbackResolver.java:110)
at org.hibernate.ejb.event.EntityCallbackHandler.addCallback(EntityCallbackHandler.java:123)
at org.hibernate.ejb.event.EntityCallbackHandler.add(EntityCallbackHandler.java:61)
at org.hibernate.ejb.event.JpaIntegrator.integrate(JpaIntegrator.java:151)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:306)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1744)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:905)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:890)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:74)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
I have found out that the root cause for the error is that the Aspect MongoDocumentBacking weaves additional PrePersist and PreUpdate methods into entity classes. Since the classes already have methods with these annotations, Hibernate Entity Manager fails to validate these classes.
Is there any guidance on how the cross-store plugin should be used with applications that have existing code that use JPA annotations?
I was facing the same issue with #PreUpdate and #PostLoad.
There is a bug opened in springsource about this:
https://jira.springsource.org/browse/DATAMONGO-519
They have given the solution below:
Create JPA entity event listener classes and move PrePersist, PreUpdate, etc. code into these listeners.
Change the aspects to first search whether an entity class has any field annotated as RelatedDocument.
If an entity class has one or more fields annotated as RelatedDocument, check whether the class already has EventListeners annotation.
If the EventListeners annotation is already present, add cross-store event listeners to the list. If not, add the EventListeners annotation to the class.
I moved all my annotations to an entity listener and it worked straight away, no need to change anything else.
Have a look at the following link, it seems that only one annotation of the same time can be added at the entity level, but many can be added using entity listeners: http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/listeners.html
#Entity
#EntityListeners(ProductEntityListener.class)
public class Product {
}
public class ProductEntityListener {
#PrePersist
#PreUpdate
protected void prePersist(Product entity) {
}
#PostLoad
protected void postLoad(Product entity){
}
}
We had the same issue here:
an EntityListener implemented an Interface with a generic parameter. After debugging the Hibernate code that threw the exception it turned out that it is not possible to use Generics in this listener interface for the entity type. After removing the generic parameter it worked.
Reason: When using a generic parameter in the interface the java compiler creates (for example) one postUpdate(...)-method for the implementing class (concrete type) and one for the interface (super type). Hibernate detects those 2, but expects only one. As a consequence it throws the exception.

Difference between JPA Entity and Hibernate Entity

When I annotate a class with #Entity and try to resolve the dependencies, I get to choose the package between two different packages, javax.persistence.Entity and org.hibernate.annotations.Entity
The javax package is JPA's entity-annotation, but why is there a hibernate entity-annotation and difference does it have with JPA's annotation? Is it just an extension to allow more attributes to be defined?
org.hibernate.annotations.Entity has some extra attributes that javax.persistence.Entity has not standarized. The extra features will only work if using hibernate's AnnotationConfiguration directly or if hibernate is the JPA provider.
from the FAQ:
edit: new link the specific question:
edit: new link the answer:
I use #org.hibernate.annotations.Entity and get an Unknown entity exception
Always import #javax.persistence.Entity
#org.hibernate.annotations.Entity completes #javax.persistence.Entity but is not a replacement
For instance, there is an attribute called optimisticLock, which tells hibernate whether to use the standard version column or to compare all columns when updating. This behavior is not in the JPA spec, so in order to configure it, you must use hibernate specific extension found in their own annotation.
Like this:
#Entity
#org.hibernate.annotations.Entity(optimisticLock=OptimisticLockType.ALL)
public class MyEntity implements Serializable {
...
}
#org.hibernate.annotations used in your project, if suppose you want to use JDBC template or ibatis we need to change the code. if we use javax.persistence there is no need to change the code. This is the main difference between org.hibernate.annotations and javax persistence
I'm not sure about the differences but I am sure that if you have the Hibernate jars in your classpath you are using Hibernate JPA. Hibernate provides an implementation of JPA. Even though you are using the javax.persistence package you are using Hibernate JPA.
The difference could be only in the naming. They might provide the same classes both in the Hibernate package space and the javax package space.

Categories