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.
- that the original class is missing an
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!