英文:
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论