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.
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?
Related
So I have an AppUser class:
#Data
#Builder
#Document(collection = "app_users")
#Component
#AllArgsConstructor
#NoArgsConstructor
#Import(AppConfig.class)
public class AppUser {
#Id
#NotBlank(message = ErrorConstants.ANDROID_USER_ACCOUNT_MANAGER_ID_IS_NULL)
private String androidUserAccountManagerId;
#NotBlank(message = ErrorConstants.NULL_NAME)
private String name;
private Friend bestFriend;
#Setter(AccessLevel.NONE)
private FriendList friendList;
private boolean manualBestFriendOverride;
public Optional<Friend> getFriend(String friendName) {
return friendList.getFriend(friendName);
}
public void calculateBestFriend() {
if (!manualBestFriendOverride) {
bestFriend = friendList.calculateAndReturnBestFriend();
}
}
}
I have created an AppUserRepository interface that extends MongoRepository:
#Repository
public interface AppUserRepository extends MongoRepository<AppUser, String> {}
I have a WebController class that interacts with the interface. The AppUserRepository field in this class is #Autowired. This all seems to work but I have a few questions regarding how, and how I go forward and write integration tests for this:
How do I configure this AppUserRepository that has been created? Can I run it on a specific port etc?
Why has the Autowiring worked as I have not created this AppUserRepository Bean in an AppConfig like I have other Beans that are Autowired in my application.
If I was to create a Bean, wouldn't I also have to implement the class and return the instantiation? I started doing this but I had to implement all of the MongoRepository classes methods which I wasn't sure seemed quite right.
How do I write integration tests with an AppUserRepository? I need an AppUserRepository for my requests to interact with, but I do not want this to be the same DB as the real-time application DB when the service is up and running. Can I #Autowire the database into the integration test class and then close the DB after the integration tests run? If this is how I go forward, I think I then need to do point 3 above.
Thanks for your help in advance, I have tried reading some documentation but I think I am missing some key knowledge that means it is all quite overwhelming and confusing.
Thanks!
That's actually quite a big story to tell. This topic is called Spring Data JPA, Hibernate. You might wanna do a research on that, and watch some tutorials and so on.
Briefly, that MongoRepository just gives you a lot of methods which you can use. You can also define your own methods, add queries and etc.
Your starting points: https://www.baeldung.com/spring-boot-hibernate
https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa
https://www.baeldung.com/spring-data-jpa-query
Of course you can set a port number (and some other properties) via application.properties file. This is a list of most common properties, you can find properties for mongodb on it:
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
Now about bean. You basically created one with #Repository annotation actually. So Spring Context loads it on the start of application. You can autowire it.
Situation
I inherited some code from a developer that seems to have used undocumented features of spring.
Specifically, it is related to using #projection functionality without actually annotating the interfaceas such.
A specific example is the following:
public interface DirType extends KeyValInterface {
#Value("#{target.id}") String getId();
#Value("#{target.code}") String getText();
}
This should not work according to the official documentation, but it does.
public interface DirTypeRepository extends JpaRepository<ABDirType, Long> {
List<DirType> findAllSummarizedBy();
}
So the method findAllSummarizedBy() of the respository is actually sending a list of DirType.
And it is using the #Valueannotations to do the mapping, but without a #Projection annotation.
The Entity class is the following:
#Data #Entity #Table(name="dir_type") #AllArgsConstructor #NoArgsConstructor
public static class ABDirType {
private #Id #GeneratedValue Long id;
private String code;
}
Question
Does anyone have any more information about this undocumented feature related to Projections and not annotating the interface as a #Projection ?
Is this possible in all versions or is it a hidden hack that is risky to use?
In Spring Data JPA (which you seem to be using here), you can simply use an interface with appropriate getters as projection targets.
See the documentation about this (esp. "Example 62. Simple Projection").
There does not seem to be a #Projection annotation anywhere in the documentation.
I have quite some JpaRepository extended Repository interfaces due to the design of the database.
In order to construct a simple object i.e Person I have to make method calls to about 4 - 5 repositories just because the data is spread like that throughout the database. Something like this (pardon for pseudocode):
#Service
public class PersonConstructService {
public PersonConstructService(Repository repository,
RepositoryTwo repositoryTwo,
RepositoryThree repositoryThree) {
public Person constructPerson() {
person
.add(GetDataFromRepositoryOne())
.add(GetDataFromRepositoryTwo())
.add(GetDataFromRepositoryThree());
return person;
}
private SomeDataTypeReturnedOne GetDataFromRepositoryOne() {
repository.doSomething();
}
private SomeDataTypeReturnedTwo GetDataFromRepositoryTwo() {
repositoryTwo.doSomething();
}
private SomeDataTypeReturnedThree GetDataFromRepositoryThree() {
repositoryThree.doSomething();
}
}
}
PersonConstructService class uses all these interfaces just to construct a simple Person object. I am calling these repositories from different methods inside the PersonConstructService class. I have thought about spreading this class into multiple classes, but I do not think this is correct.
Instead I would like to use a repositoryService which would include all the repositories listed necessary for creation of a Person object. Is that a good approach? Is it possible in Spring?
The reason I am asking is that sometimes the count of injected Services into a class is about 7-8. This is definitely not good.
I do not think you can / shoudl create a meta-repository like abstraction. Repositories have a well defined meaning, conceptually, they are CRUD services (and a bit more sometimes :-)) for your Hibernate/JPA/Datastore entities. And I guess this is enough for them. Anything more is confusing.
Now what I would propose is a "smart" way of building your "Person" objects that is automa(g)tically aware of any new services that contribute to the meaning of the Person object.
The crux of it would be that :
you could have your Repositories implement a given Interface, say PersonDataProvider, which would have a method, say public PersonPart contributeDataToPersonBuidler(PersonBuilder).
You would make your #Service implement Spring's BeanFactoryPostProcessor interface, allowing you to inspect the container for all such PersonDataProvider instances, and inject them to your service (see accepted answer at How to collect and inject all beans of a given type in Spring XML configuration)
Your #Service implementation would then be to ask all the PersonDataProviders in turn to ask them to contribute their data.
I could expand a bit, but this seems to me like the way to go.
One could argue that this is not clean (it makes your Repositories aware of "something" that happens at the service layer, and they should not have to), and one could work around that, but it's simpler to expose the gist of the solution that way.
EDIT : since this post was first written, I came aware that Spring can auto-detect and inject all beans of a certain type, without the need of PostProcessors. See the accepted answer here : Autowire reference beans into list by type
I see it as a quite reasonable and practical data aggregation on Service layer.
It's perfectly achievable in Spring. If you have access to repositories code you can name them all like:
#Repository("repoOne")
public class RepositoryOne {
#Repository("repoTwo")
public class RepositoryTwo {
And inject them into the aggregation service as necessary:
#Service
public class MultipleRepoService {
#Autowired
#Qualifier("repoOne")
private RepositoryOne repositoryOne;
#Autowired
#Qualifier("repoTwo")
private RepositoryTwo repositoryTwo;
public void doMultipleBusiness() {
repositoryOne.one();
repositoryTwo.two();
}
}
In fact, you even don't need to name and Qualify them if they are different classes, but if they are in hierarchy or have the same interface...
Also, you can inject directly to constructing method if autowiring is not a case:
public void construct(#Qualifier("repoOne")RepositoryOne repoOne,
#Qualifier("repoTwo")RepositoryTwo repoTwo) {
repoOne.one();
repoTwo.two();
}
I want to create an app following the DDD approach using Spring. Supose that I have a business model class Foo and an interface FooRepository.
DDD tells that the implementation of FooRepository should include in Infrastructure layer.
I would want to use CrudRepository but if I define in the domain layer:
public interface FooRepository extends CrudRepository<Foo, Long>{
// Some methods
}
I break with the core concept that the domain layer (FooRepository interface) must not know the infrastructure layer (CrudRepository).
I'm reading about this Domain Driven Design a few months ago but I haven't found a framework that supports it purely.
How I can do it the right way?
In the layered architecture you usually have 3 layers: application, domain and infrastructure.
Infrastructure
Here I put the implementation of the repository. In your case this is the implementation of CrudRepository which I would implement directly in concrete classes, without the use of an intermediate interface. We make no whatsoever assumption as to how the single object in the warehouse behave, we only put them there and retrieve them efficiently. This way we have no knowledge of the domain. We only offer the domain an interface to interact with: the set of public methods of WarehouseRepository.
public class WarehouseRepository implements CrudRepository<Foo, Long> {
...
}
Domain
Here various part of the model interact with the WarehouseRepository when you are inside a UnitOfWork/Transaction. In the method adjustQuantityPlus we se only domain logic which is not interesting to the application and need not to be known at infrastructure level.
public class SaleOrder {
public adjustQuantityPlus(LineItemID lineItemID,
WarehouseRepository warehouseRepository) {
this.lineItems.get(lineItemID).addOne(); //<-- add one to the order
Product product =
warehouseRepository.findByLineItem(lineItem);
product.minusOneFromStock(); //<-- decrease one from stock
}
}
Application
Here we start and stop transactions (UOWork) which manipulates many domain objects. Every business method correspond to a business use case.
public class CustomerEventsManager {
#Inject WarehouseRepository warehouseRepository;
#Inject SaleOrderRepository saleOrderRepository;
#Transactional
public wantsOneMoreOf(ProductID productID, SaleOrderID saleOrderID) {
SaleOrder saleOrder =
saleOrderRepository.findByID(saleOrderID)
saleOrder.adjustQuantityPlus(productToLineItem(productID),
warehouseRepository); //<-- add product
webPage.showPromoDiscount(); //<-- show promotional advertisement
}
}
The above code is a transaction, if the system couldn’t add the product to the order I don’t want to give the discount to the customer. The adjustQuantityPlus in turn is an inner “transaction” with domain logic, hidden to the application layer.
i have a small code generation question.
I have a EJB3 backend that serves DTO objects to a frontend. The frontend uses a configurable binding procedure to map the attributes of the DTO to their forms.
At the moment they are doing it by specifing the attributes as strings in ther configuration. The binding implementation uses reflection to acces the attributes.
Sounds nice but the problem is, each time we change an attribute name in a DTO, this will not lead to a compile error in the frontend because they have just strings.
I'm now looking for a way to create a string constant for each attribute of the class that can be used by the frontend to map the attributes to their forms so that they get compile errors if i made changes in the dto attributes.
Example how it is:
public class CarDTO {
private String vendor;
private String name;
public String getVendor() {}
public String getName() {}
[..]
}
And how it should be:
public class CarDTO {
public static final String VENDOR = "vendor";
public static final String NAME = "name";
private String vendor;
private String name;
public String getVendor() {}
public String getName() {}
[..]
}
I was looking for a maven plugin that is capable of this but without success. Is there any one who nows a tool which can do things like that?
Thanks in advance
martin
Modifying existing class is more difficult then creating new one.
JPA took a interesting approach to solve this problem by creating CarDTO_ class. See http://www.hibernate.org/subprojects/jpamodelgen.html for more details. This approach is much easier. You can look at the hibernate maven plugin that implement the code generation.
If you really want to modify the existing class, then I would recommend using AspectJ with an approach similar to Spring Roo, where the aspect contains the generated code.
Edited (Example using AspectJ)
In this case, we are using AspectJ inter-type declarations that enables you to modify an existing class.
aspect CarAspect
{
public static final String CarDTO.VENDOR = "vendor";
public static final String CarDTO.NAME = "name";
}
Do implement this in maven, you need
a plugin to generate the CarAspect
the aspectj-maven-plugin to compile (weave) the aspect
Also, Eclipse has good support for AspectJ so you can use it there too.
I have a app with a similar frontend approach to access the domain classes, but I have my domain is entirely created via a DSL implemented via Eclipse Xtext, who can be used in a maven build also. There is a sample Java domain DSL project in the xtext distribution, its easy to start from there.
This sure is not a fast "just use a maven plugin" solution but once you get into Xtext it will pay off, especially if you have a lot domain classes, or a lot similar projects.
From my domain DSL I create via code templates and a xtext generator project three classes:
target/generated/mydsl (generated always):
AbstractDomainClass (in this file i have my static string's)
src/main/java (generated once):
ConcreteDomainClass
src/test/java (generated once):
ConcreteDomainClassTest
In the abstract domain class i have all getters and setters and simple persistence stuff in it, in the concrete domain class is the more complex stuff and the test class stands for it self.