Is it possible to provide annotation based hibernate mapping informations for external classes?
I have a model class (for example Credit) in an external package (without any dependencies to hibernate) which I can't / wan't edit and now I wan´t to define mapping informations for this class.
It's no problem to define these mapping informations in a xml file but I am looking for a possibility to define these informations via annotations.
I can extend the model class but then the child class is mapped but i wan't to map the superclass.
Related
What's the best practice to create persistence (say via Spring Boot or just JPA or Hibernate itself) for a data model coming from a non-modifiable dependency? Typical limitations like not being able to override a field or what patterns like Decorator allow and what not slowed my progress down. I tried some things, but I always end up with the result that it would be necessary to either modify the source model (like adding annotations to make it natively compatible -> the fork I don't want) OR write a ton of wrapper code which would replicate the original model too much - but even this isn't working right now:
I tried
Creating a JpaRepository for the original class. Doesn't work, because casting the extended class to its parent class is not working.
Extend the original class with a custom class that gets necessary annotations like #Entity can be used in such a repository. But problems here were
that the original class is missing an #Id annotation, which could be fixed by using a new ID in the extended class, but
the given model also has a non-simple architecture, including lists of other classes that are part of the model itself. So other annotations like #ElementCollection might be necessary, which can't be added because overriding of fields is not possible.
Hiding it with creating a new field with the same name in the new class is not working:
An error like Could not determine type for: java.util.List, at table: yeah_this_one, for columns:[org.hibernate.mapping.Column(objects)] indicates that the original field can't be hidden completely (changed table and column name in new class to verify that).
So of course adding #ElementCollection (which is said to solve that) isn't helping here, too.
#AttributeOverride is also not working to override annotations to set the ID or other settings, only the name and column can be changed.
I'm stuck at this state and am wondering if this is even the right approach at all.
The setup or what I would expect to work from my understanding:
The general idea is based on this Spring Boot REST tutorial, which I tried to expand with a model from a dependency.
Let's assume there is the original model class Model from a dependency that can not be modified. The ModelEntity would be the extended class to act as way to pull the model into Spring persistence.
In the scope of the dependency the original class would be like:
// Given dependency, not modifiable
#Some existing annotation
public class Model extends AnotherClassFromDep {
#more annotations
private IdLikeClassFromDep modelId;
//more complex attribute
#Nullable
private List<RefClassFromDep> objects = new ArrayList<>();
// more attributes, getter, setter etc.
}
In the scope of my program:
In combination with this little additional orm.xml it is possible to annotate the original Model as MappedSuperclass without modifying it (according to https://stackoverflow.com/a/2516951/1844976).
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
<mapped-superclass class="package.name.of.original.Model">
</mapped-superclass>
</entity-mappings>
This allows to create a class like this, which extends the original POJO model to add JPA annotations:
#Entity
public class ModelEntity extends Model {
// some #Id attribute is necessary, which should correspond to
// the already existing ID attribute from the original `Model`
// in the best case, but an additional one would work too
private #Id #GeneratedValue Long id;
// Different approaches to solve the List error from above, for
// instance hiding the original attribute
#ElementCollection
private List<RefClassFromDep> objects;
public ModelEntity(){
super();
}
}
At the current state the issues are blocking me from going further. But, altogether I would expect this to work with a JpaRepository:
// of course, creating a JpaRepository with original `Model` wouldn't
// work, because it has no `#Entity`
public interface ModelRepository extends JpaRepository<ModelEntity, IdLikeClassFromDep> {
}
In a way that actually accessing it like that is possible:
#Configuration
public class LoadDatabase {
#Bean
CommandLineRunner initDatabase(ModelRepository modelRepository) {
return args -> {
// depending on the implementation above, either create a
// Model and cast it or directly create a ModelEntity, set
// attriubtes and save it through the JpaRepository
modelRepository.save(model);
};
}
}
Both more abstract and specific code-related ideas and comments would help me. Thanks!
In the old days, Jpa/Hibernate were configured via XML.
You needed to provide persistence.xml for general configuration. In this file, you added <mapping-file> tag pointing to another file orm.xml In this file you configured mapping for your entities (which is done via JPA annotations these days).
See https://vladmihalcea.com/how-to-use-external-xml-mappings-files-outside-of-jar-with-jpa-and-hibernate/
While the methods described above are considered legacy, they are still supported. LocalContainerEntityManagerFactoryBean has method setMappingResources allowing you to point to the orm.xml file. There is some funkiness about search paths and default locations, but it is well documented:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html#setMappingResources-java.lang.String...-
Note that the third-party class you are configuring this way needs to conform to Java Beans conventions (no-args constructor, getters and setters)
I need to retrieve data from legacy Couchbase bucket without a specific schema. It can be mapped as com.couchbase.client.java.document.StringDocument from the Couchbase Java client. I can do this directly using Java client:
bucket.get(key, StringDocument.class)
But how can I map this StringDocument using org.springframework.data.repository.CrudRepository?
I can't create such interface interface UserRepository extends CrudRepository<StringDocument, String> because Spring Data Couchbase requires #Document and #Id annotations.
All entities should be annotated with the #Document annotation. Also, every field in the entity should be annotated with the #Field annotation. While this is - strictly speaking - optional, it helps to reduce edge cases and clearly shows the intent and design of the entity.
There is also a special #Id annotation which needs to be always in place. Best practice is to also name the property id.
Should I directly use Bucket, create my own similar entity, or there is another solution?
I use following version of spring-boot-starter-data-couchbase: 1.5.9.RELEASE.
If its just a StringDocument (and it wasn't even saved by spring-data-couchbase to begin with.. which injects the _class attribute for deserialization purposes) then I'd just use the bucket to retrieve it.
Keep in mind if your repository (I'm talking about any other repository you have defined that is mapped to the same bucket the StringDocument is in) is defined as CouchbaseRepository you will be able to access the bucket itself from the repository methods like so repository.getCouchbaseOperations().getCouchbaseBucket(). Or maybe you can try the following repository.getCouchbaseOperations().findById("id", StringDocument.class).
Does MongoDB (specifically the Morphia ORM) support any class mapping features like gson's type adapter, I'm trying to map a class that contains some fields that I don't want to store.
You can annotate fields with #Transient and they won't get mapped.
I'm trying to convert a legacy application to hibernate.
I have an entity that has a field, which should be instantiated to object instance based on a fully qualified name string in a database.
Consider the example below - if I have somePackageName.FirstClass in a database the someObject field should be an instance of FirstClass.
I guess I could use property access and persist / retrieve a string but that doesn't look very elegant to me.
I cannot use #PostLoad etc. - I'm using pure hibernate with spring (not JPA) - these annotations get ignored.
I know for example in MyBatis one can register a custom handler for field. Would anything similar be available in Hibernate?
I'm new to hibernate so I'm not really sure what the options are.
#Entity
class SomePersistentClass{
private SomeInterface someObject;
}
class FirstClass implements SomeInterface{
}
class SecondClass implements SomeInterface{
}
You can use JPA features such as #PostLoad, etc callbacks simply by enabling the proper Hibernate event listeners. Check the Hibernate EntityManager guide for details.
But this one is even easier. This is the role of a Type in Hibernate. First, you'll have to write an implementation of org.hibernate.type.Type or org.hibernate.usertype.UserType and specify that in #Type( type=... ) that handles the conversions (lots of web resources about writing custom Hibernate types). Then annotate your 'someObject' attribute with #Type( type="your.custom.TypeImpl" )
Jpa one of the big successfull module of jpa and so are its annotation features .I have weird requirement in which i need to create jpa annotation ,one that jpa can process
ex. We have in jpa a table annotation that create a table for this java pojo class.
i need to make another annotation that behaves exactly as what table annotation does + some of my custom reqirements;
what is mean
if i create a customAnnotation like #Anil that is suppose to work same as #Table Annotation does
than
#Anil
public class Anp
{
}
than this should create a table in the database is that possible or not .if it is give me some way to do this
thanks
JPA does not process just any annotation. The JPA implementation processes the annotations that it supports and these are typically just the javax.persistence annotations, and optionally its own extensions. Your JPA provider may allow you to define your own, but this is not going to be very common - look at the docs for your JPA provider if they allow a user to define annotations.
For example, the JPA provider I have used (DataNucleus JPA) allows the user to provide annotations for the class or for the field/property.