英文:
Mixing in Spring Data Annotations
问题
随着我逐渐努力在我的库的领域部分中删除对Spring的依赖,我现在转向Spring Data和Repositories。
最初,我们对领域实体进行了如下注释:
@Document
public void MyEntity {
@Id
@Getter private final EntityIdentifier identifier;
@PersistenceConstructor
public MyEntity( ... ) {}
...
}
以此类推。其中 @Document
、@PersistenceConstructor
和 @Id
来自Spring项目,其中一些是针对特定数据库后端(如MongoDB)的。
我想要削减这种依赖,并且使用我自己的注释,以便在我的领域中更有意义。例如,@Document
绝对不是我领域专家在类似于 Chair
或 Desk
这样的类上会理解的内容。
对于使用Jackson进行序列化/反序列化,我可以创建 mixins 来为类添加特定的注释,而无需修改它们的源代码。也许在Spring中有类似的技术或其他实现方法,比创建包装类更加优雅?
显然我需要一些澄清:
假设我们尝试编写一个干净架构的应用程序,由以下模块组成:domain
、adapters
、application
。在 domain
模块中,我有我的领域逻辑和领域实体,以及一切与领域相关的内容。我没有任何与Spring相关的内容 - 完全没有依赖于Spring,甚至没有任何以某种方式依赖于Spring的依赖。
在 adapters
和 application
模块中,我有与Spring相关的依赖。我可能会使用Spring Data来实现存储库适配器。我将使用Spring来配置和组合应用程序。
现在,在我的domain模块中,我有以下类:
@AllArgsConstructor
@HashAndEquals(of="identifier")
@DomainEntity // <-- 这是一个没有依赖于Spring的注释!
public class DomainEntity {
@DomainId // <-- 这是一个没有依赖于Spring的注释!
@Getter private final DomainEntityIdentifier identifier;
@Getter @Setter private String someValue;
...
}
@HashAndEquals
@AllArgsConstructor
public class DomainEntityIdentifiers {
@Getter private final String name;
}
public interface DomainEntityRepository {
DomainEntity findById(DomainEntityIdentifier identifier);
void save(DomainEntity domainEntity);
void deleteById(DomainEntityIdentifier identifier);
}
现在的任务是,在 adapters
模块中为该接口提供实现,使用Spring Data,比如 spring-data-mongo
,并将此适配器注入到 application
模块中的领域中。
当然,我可以创建一个类,比如说 DomainEntityMongo
,基本上与 DomainEntity
相同,只是加了spring-data-mongo的注释,然后创建一个 public interface MyEntityRepository extends CrudRepository<EntityIdentifier, MyEntityMongo>
,并通过使用 MyEntityRepository
来实现 DomainRepository
接口,在两者之间进行转换。
我正在寻找的是一个更为神奇/通用的解决方案。例如:
- 像Jackson样的mixin类,为Spring提供必要/缺失的元数据来完成工作
- 配置Spring以使用非Spring注释来完成工作(就像对非组件继承注释进行组件扫描一样)
- 或者 - 如果数据团队提供了另一种创新的解决方案 - 这个创新的解决方案。
英文:
As I am gradually trying to remove Dependencies on Spring in the domain part of my library without minimal extra effort, I now turn to Spring Data and the Repositories
Originally we annotated our domain entities to look like this:
@Document
public void MyEntity {
@Id
@Getter private final EntityIdentifier identifier;
@PersistenceConstructor
public MyEntity( ... ) {}
...
}
and so on.
where @Document
, @PersistenceConstructor
and @Id
originate from the Spring Project and some are for a specific database backend (MongoDB).
I would like to cut this dependency and use my own annotations, that make sense in my domain - @Document
is definitly nothing my domain experts would understand when appearing on e.g an clas Chair
or a Desk
.
For de/serialization with Jackson, I can create mixins to add specific annotations to classes without modifying them in their origin.
Maybe there is a similar technique for Spring or some other way to achive this that is more elegant than creating a wrapping class?
Apparently I need some clarification:
Lets suppose we try to write a clean architecture application which consists out of the following modules: domain
, adapters
, application
. In the domain
module, I have my domain logic and domain entities and everything domainy. I do not have anything springy - no dependency on spring whatsoever, not even by having a dependency that somehow depends on spring.
In the adapters
and application
module, I do have dependencies on spring. I might use spring-data to implement the Repository-Adapters. I will use Spring to configure and glue together the application.
Now, in my domain module I have the following classes:
@AllArgsConstructor
@HashAndEquals(of="identifier")
@DomainEntity // <-- This is an Annotation that has no dependency on Spring!
public class DomainEntity {
@DomainId // <-- This is an Annotation that has no dependency on Spring!
@Getter private final DomainEntityIdentifier identifier;
@Getter @Setter private String someValue;
...
}
@HashAndEquals
@AllArgsConstructor
public class DomainEntityIdentifiers {
@Getter private final String name;
}
public void interface DomainEntityRepository {
DomainEntity findById(DomainEntityIdentifier identifier);
void save(DomainEntity domainEntity)
void deleteById(DomainEntityIdentifier identifier);
}
Now the task is, to provide the implementation of that interface in the adapters
module, using Spring Data - e.g. spring-data-mongo
and inject this adapter to the domain in the application
module.
Now, surly I can create an class, lets say DomainEntityMongo
which is basically the same as the DomainEntity
just with the spring-data-mongo-annotations, then a public interface MyEntityRepository extends CrudRepository<EntityIdentifier, MyEntityMongo>
and implement the interface DomainRepository
by using MyEntityRepository
and converting there and back again between DomainEntityMongo <=> DomainEntity
.
What I am looking for is a more magical/generical solution. E.g.
- Having jackson-style mixin-classes, which provide Spring with the necessary/missing meta-data to do the work
- Configuring Spring to use non-spring-annotations to do the work (just as it is possible with the ComponentScan for non-component-inheriting Annotations)
- Or - if the data guys have crafted another innovative solution - this innovative solution.
答案1
得分: 1
你可以使用
@JsonDeserialize(using = yourCustomizedDeserializer.class)
在这里查看
https://www.baeldung.com/jackson-deserialization
你可以使用 @Persister 自定义持久化策略。例如,您可以指定自己的 org.hibernate.persister.EntityPersister 子类,甚至可以提供完全新的 org.hibernate.persister.ClassPersister 接口实现,通过存储过程调用、序列化到平面文件或 LDAP 实现持久化。
这是否是您正在寻找的内容?
英文:
you can use
@JsonDeserialize(using = yourCustomizedDeserializer.class)
have a look here
https://www.baeldung.com/jackson-deserialization
you can customize your persistence strategy with @Persister. You may, for example, specify your own subclass of org.hibernate.persister.EntityPersister or you might even provide a completely new implementation of the interface org.hibernate.persister.ClassPersister that implements persistence via, for example, stored procedure calls, serialization to flat files or LDAP.
is that what you are looking for?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论