在Spring Data注解中进行混合使用

huangapple go评论93阅读模式
英文:

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 绝对不是我领域专家在类似于 ChairDesk 这样的类上会理解的内容。

对于使用Jackson进行序列化/反序列化,我可以创建 mixins 来为类添加特定的注释,而无需修改它们的源代码。也许在Spring中有类似的技术或其他实现方法,比创建包装类更加优雅?


显然我需要一些澄清:

假设我们尝试编写一个干净架构的应用程序,由以下模块组成:domainadaptersapplication。在 domain 模块中,我有我的领域逻辑和领域实体,以及一切与领域相关的内容。我没有任何与Spring相关的内容 - 完全没有依赖于Spring,甚至没有任何以某种方式依赖于Spring的依赖。

adaptersapplication 模块中,我有与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=&quot;identifier&quot;)
@DomainEntity  // &lt;-- This is an Annotation that has no dependency on Spring!
public class DomainEntity {
    @DomainId // &lt;-- 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&lt;EntityIdentifier, MyEntityMongo&gt; and implement the interface DomainRepository by using MyEntityRepository and converting there and back again between DomainEntityMongo &lt;=&gt; 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?

huangapple
  • 本文由 发表于 2020年10月13日 20:06:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/64334936.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定