Skip to content

Instantly share code, notes, and snippets.

@jrdalpra
Last active August 29, 2015 14:08
Show Gist options
  • Save jrdalpra/07221f68a966f1762b89 to your computer and use it in GitHub Desktop.
Save jrdalpra/07221f68a966f1762b89 to your computer and use it in GitHub Desktop.
Clean Architecture Ideas.java
interface Processor<Request,Response> {
Response process(Request request);
}
class UserRepositoryThatUsesJPA implements UserRepository {
EntityManager entities;
Converter<User,UserEntity> toEntity;
Converter<UserEntity,User> toUser;
User save(User user){
UserEntity entity = toEntity.convert(user);
if (entity.isNew()){
entities.persist(entity);
return toUser.convert(entity);
}
UserEntity merged = entities.merge(entity);
return toUser.convert(merged);
}
}
class SaveNewUserProcessor implements Processor<SaveNewUser.Request, SaveNewUser.Response> {
UserRepository users;
Iterable<Validator<SaveNewUser.Request>> requestValidators
SaveNewUser.Response process(SaveNewUser.Request request){
validate(request);
User newUser = request.getNewUser();
User saved = users.save(newUser);
return new SaveNewUser.Response(saved);
}
validade(SaveNewUser.Request request) NotValid {
for(Validator<SaveNewUser.Request> validator : requestValidators)
validator.validate(request);
}
}
// I can implement alternatives or wrap
class LogArroundCallSaveNewUserProcessor implements Processor<SaveNewUser.Request, SaveNewUser.Response> {
Processor<SaveNewUser.Request, SaveNewUser.Response> officialImplementation;
SaveNewUser.Response process(SaveNewUser.Request request){
log("before save " + request);
SaveNewUser.Response response = officialImplementation.process(request);
log("before send " + response);
return response;
}
}
// I can compose processors
class SaveNewProfile implements Processor<SaveNewProfile.Request, SaveNewProfile.Response> {
Processor<SaveNewUser.Request,SaveNewUser.Response> saveNewUser;
Processor<UploadPicture.Request,UploadPicture.Response> uploadPicture;
SaveNewProfile.Response process(SaveNewProfile.Request request){
User savedUser = saveNewUser.process(new SaveNewUser.Request(request.getUserInfo()));
Picture uploadedPicture = uploadPicture.process(new UploadPicture.Request(request.getAttachedPicture()));
return new SaveNewProfile.Reponse(savedUser,uploadedPicture);
}
}
class ListUsersProcessors implements Processor<ListUsers.Request,ListUsers.Response>{
UserRepository users;
ListUsers.Response process(ListUsers.Request request){
PageOf<User> page = users.listBy(request.getCriteria());
return new ListUsers.Response(page);
}
}
// I can iterate
class ChainOfProcessors {
Iterable<Processor<SaveNewUser.Request,SaveNewUser.Response>> processors;
SaveNewUser.Response process(SaveNewUser.Request request){
for(processor : processors){
// do something with each processor
}
}
}
// I can produce to user at CDI env
class ProcessorsProducer {
@Produces
@RequestScoped
@Inject
Processor<SaveNewUser.Request,SaveNewUser.Response> saveNewUser(UserRepository repository){
return new SaveNewUserProcessor<>(repository);
// or compose return new LogArroundCallSaveNewUserProcessor<>(new SaveNewUserProcessor<>(repository));
}
}
// I can use at REST endpoint
@Path("/users")
class UsersResource {
@Inject
Processor<SaveNewUser.Request,SaveNewUser.Response> saveNewUser;
@Inject
Processor<ListUsers.Request,ListUsers.Response> listUsers;
@Inject
Converter<PageOf<User>,List<UserResource>> toUserResources;
@Post
UserResource save(User user){
SaveNewUserResponse response = saveNewUser.process(new SaveNewUser.Request(user));
return new UserResource(response.getSaveUser());
}
@Get
List<UserResource> list(Pagination pagination){
return toUserResources.conver(listUsers.process(new ListUsers.Request(pagination)).getPageOfUsers());
}
}
package test;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.val;
public class Test {
static interface Case<O> {
}
static interface Implementation<C extends Case<O>, O> {
O run(C case_);
}
@RequiredArgsConstructor(staticName = "where")
static class Clause {
Clause property(String name, Object value) {
return this;
}
}
static class Query {
static class One<E> implements Case<Return.One<E>> {
public One<E> using(Clause clause) {
// TODO Auto-generated method stub
return null;
}
}
static class Return {
static class One<E> {
E found;
}
public class PageOf<E> {
}
}
}
static class User {
String login;
String password;
@RequiredArgsConstructor(staticName = "query")
static class One extends Query.One<User> {
}
}
@RequiredArgsConstructor(staticName = "a")
static class Save<E> implements Case<Reponse<E>> {
public final E toSave;
public static <E> Save<E> an(E toSave) {
return a(toSave);
}
@RequiredArgsConstructor(staticName = "_")
static class Reponse<E> {
public final E saved;
}
}
@RequiredArgsConstructor(staticName = "some")
static class BatchSave<E> implements Case<Reponse<E>> {
public final List<E> toSave;
@RequiredArgsConstructor(staticName = "_")
static class Reponse<E> {
public final List<E> saved;
}
}
static class WarnAbout<E> implements Case<Void> {
E event;
}
private static Implementation<Save<User>, Save.Reponse<User>> users;
private static Implementation<Query.One<User>, Query.Return.One<User>> finder;
public static void main(String[] args) {
new Implementation<WarnAbout<User>, Void>() {
@Override
public Void run(WarnAbout<User> input) {
// TODO Auto-generated method stub
return null;
}
};
val result = finder.run(User.One.query());
if (result.found.login.equalsIgnoreCase("x"))
;
val response = users.run(Save.an(new User()));
System.out.println(response.saved);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment