Groovy Mixin persistent properties with JPA - jpa

I would like to define a JPA persisted property in a Groovy Mixin and then use it in several entity classes. I couldn't get this to work with JPA annotations and Hibernate - has anyone been successful with this combination?
I have a set up an example Maven project which shows what I'm trying to do and a single JUnit test which defines the behavior I would like.
https://github.com/gilday/groovy-mixin-jpa-test
Briefly:
#Category(Person) class HasPreferences {
#ElementCollection
final Collection<Preference> preferences = []
}
#Entity
#Mixin(HasPreferences)
class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id
String name
}

Since #Mixin is dynamic, i doubt JPA will be able to find your mixed properties. I think you need some compile-time code generation, like #Delegate. Even so, JPA will try to persist the generated property. There is a discussion in groovy mailing list concerning the creation of a #Trait annotation which might be what you want.

Related

Using #Id on methods

I would like to annotate a method with Spring Data #Id but it only works with fields, despite the fact that the annotation can be used on methods.
Is there a way to use #Id on methods too?
I'm using Spring Boot 1.3.0.RELEASE
EDIT
Actually I have this interface that will have an instance being created at runtime.
import org.springframework.data.annotation.Id;
#Document(indexName = "index", type = "document")
public interface Document {
#Id
Integer getId();
}
And this repository.
public interface DocumentRepository extends ElasticsearchCrudRepository<Document, Integer> {
}
Problem is that SimpleElasticsearchPersistentProperty from spring-data-elasticsearch 1.3.0.RELEASE always look for fields:
https://github.com/spring-projects/spring-data-elasticsearch/blob/1.3.0.RELEASE/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java
That way if I create an asbtract class instead and put #Id on a field, everything works fine.
The #Id annotation does work on properties, i.e. you can put it on getters, setters or fields. If this does not work something is wrong. Possible reasons are:
the names don't fit the property conventions
you are using the wrong #Id annotation
It does not work on arbitrary methods because Spring Data wouldn't be able to determine a name for that non-property, which in turn is required for many features.

Can JpaRepository take entity description from *.hbm.xml files?

I write application using hibernate, spring-boot-data-jpa and spring-boot-data-rest.
My entity classes are not contain any annotations, and all orm mapping placed in several hbm.xml files.
class MyEntity {
Long id;
String name;
}
interface MyRepository extends JpaRepository<MyEntity, Long> {
}
Hibernate working fine, as well as all methods of JpaRepository like findOne. The problem that the rest interface provided by JpaRepository say
"PersistentEntity does not have an identifier property!".
I found that adding #Id to MyEntity class solves the problem. However, I prefer define orm mapping in hbm.xml file, not using annotations.
How can I configure JpaRepository's to consider *.hbm.xml files?
I faced similar problem with JpaRepository using hbm files. JpaRepository can accept hbm files if these are present in resource folder. In resources folder, create any folder say resources/hbm and move all hbm file to this folder. Now hbm files will be found by JpaRepository and not an managed type error will be fixed.

Spring Data JPA repository methods don't recognize property names with underscores

I have underscores in the entity property names, and when Spring tries to create the JPA repository implementation, it results in an exception trying to resolve the name of the property.
Entity:
#Entity
public class Student {
#Id
private String s_id;
private String s_name;
...
}
Repository:
#Repository
#Transactional
public interface StudentRepository extends CrudRepository<Student, String> {
List<Student> findByS__name(String name);
}
Exception:
org.springframework.data.mapping.PropertyReferenceException:
No property s found for type Student
It is said here http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
If your property names contain underscores (e.g. first_name) you can
escape the underscore in the method name with a second underscore. For
a first_name property the query method would have to be named
findByFirst__name(…).
I just did as document said, but I still got the exception.
I dont want write #Query by myself, and I need underscore in my property name, how to fix this problem?
I use Spring data jpa 1.8.0.RELEASE + hibernate 4.3.9.Final
Avoid using underscores in the entity property names if you have control over the property naming. This will resolve your repository woes, and will result in a cleaner code-base. Developers dealing with the code after you will thank you.
Note, it's not just my opinion: Spring specifically discourages using underscores.
As we treat underscore as a reserved character we strongly advise to
follow standard Java naming conventions (i.e. not using underscores in
property names but camel case instead).
this JIRA issue shows why the documentation was updated with this reccomendation, and the part describing the double underscore option were removed.
I suspect your root problem is that Spring/Hibernate is not mapping camel case property names to the snake case names you have for your columns in the database. What you really need is for your property name to be interpreted in the SQL that hiberate generates as S_NAME.
Is that why underscores in your property name are "required"? If so, there are a few solutions:
Option 1: #Column annotation
To get JPA/Hibernate to map to the correct column names you can tell it the names explicitly. Use the annotation #Column(name="...") to tell it what column names to use in SQL. Then the field names are not constrained by the column names.
#Entity
public class Student {
#Id
#Column(name="s_id")
private String sId;
#Column(name="s_name")
private String sName;
//...getters and setters...
}
Option 2: Improved Naming Strategy
Or if your application has a large number of entities, rather than adding #Column to every property, change the default naming strategy in your configuration file to the hibernate improved naming strategy.
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
This naming strategy will convert camelCase to SNAKE_CASE. Then your class could look as simple as this:
#Entity
public class Student {
#Id
private String sId;
private String sName;
//...getters and setters...
}
Using either of those options, when it creates the SQL it will resolve the column names to:
S_ID
S_NAME
Note: If you are using, or can use Spring Boot, the auto-configuration default will use SpringNamingStrategy, which is a slightly modified version of the hibernate improved strategy. You won't have to do anything to get this improved naming strategy.
The finish line:
Using camel case in your property names you can write your repository method name using camel case, and you can stop trying to wrangle the double underscore:
#Repository
#Transactional
public interface StudentRepository extends CrudRepository<Student, String> {
List<Student> findBySName(String name);
}
Writing double underscore i.e. writing findByS__Name() for property name s_name just does not work. I have tried and tested it. Go by the above answer and change the name of existing instance variables in your entity class. Just dont change getters and setters as they might be used in the existing code.
If you cant change the entities which was my case then better use jqpl query or native sql query on top of repository method
#Query("select s from Student s where s.s_name=?")
List<Student> findBySName();

Why is my projection interface not picked up by Spring Data REST?

I am trying to use up projections with Spring Data REST (version 2.3.0.RELEASE). I read the reference documentation, and gathered that these are the parts I need:
A JPA Entity
#Entity
public class Project implements Serializable {
#Basic(optional = false)
#Column(name = "PROJECT_NAME")
private String projectName;
// ... lots and lots of other stuff
}
A repository that works with that entity
#Repository
public interface ProjectRepository extends JpaRepository<Project, Long> { }
And a projection to retrieve just the name for that entity
#Projection(name="names", types={Project.class})
public interface ProjectProjectionNamesOnly {
String getProjectName();
}
I would like to be able to optionally retrieve just a list of names of projects, and projections seemed perfectly suited to this. So with this setup, I hit my endpoint at http://localhost:9000/projects/1?projection=names. I get back ALL of the attributes and collections links, but I expected to get back just the name and self link.
I also viewed the sample project on projections, but the example is for excerpts, which seems different from projections as it is a different section of the reference. I tried it and it didn't work anyway though.
So the question is this: How do you use spring data rest projections to retrieve just a single attribute of an entity (and its self link)?
Looks like your projection definition is not even discovered and thus it doesn't get applied if you select it for the HTTP request.
For projection interfaces to be auto-discovered they need to be placed inside the very same or a sub-package of the package of the domain type they're bound to.
If you can't put the type into that location, you can manually register a projection definition on RepositoryRestConfiguration by calling ….projectionConfiguration().addProjection(…).
The reference documentation does not really mention this at the moment but there's already a ticket to get this fixed in future versions.

JPA validation problem: Entity 'X' has no Id or EmbeddedId

Which, I couldn't quite figure out why Eclipse Galileo's JPA validator would say so, as my class 'X' clearly had an #Id annotation on the primary key "uniqueId". The error would disappear if I commented out the #Basic annotation line, but that didn't quite make sense. Anyway, attaching snippet below from memory:
#Entity
class X {
...
#Id
#Basic(optional=false)
#Column(name="someUniqueId", unique=false)
String uniqueId;
...
}
Is this a bug, or is there a JPA standard which I'm not aware of on the use of annotations?
You have here a similar case which may suggest a case or type issue.
But as mentioned here, I would rather bet on bug 217192 (which can be comared with the "non-bug" 208249)
You can also specify which version of eclipse and Dali JPA Tool you are using.
#EmbeddedId
String uniqueId;
You annotated the "uniqueId" with "unique=false".
This could be the root because IDs have to be unique.
You do not need a #Basic annotation as #Id already restricts the attribute's type (as defined by the spec) and the only information #Basic can add are settings for fetch and optional both of which make no sense for a primary key (i.e. a primary key must have fetch=EAGER and optional=false).