I have an entity type with several fields. Some of them are references to other entities. I want to create a Rest API endpoint in Spring that lets users to update entities of this type.
Assume that I have an entity User that contains a list of friends. I only want to let users update some specific fields, such as name, age and description, of a user entity, and not list of friends.
Besides, I only want those attribute of the entity to be updated that the corresponding passed in values are not null.
public class UserController {
#RequestMapping(path="",method=RequestMethod.PUT)
public void update(#RequestBody User user) {
userService.save(user);
}
}
How can I make this possible ?
Instead of taking User object as a parameter in your update() method you can take a DTO class that only defines the properties you need to change.
Define a class UpdateUserDTO like so
public class UpdateUserDTO {
private String name;
private String description;
//other fields you want the clients to change.
...
}
Now this UpdateUserDTO can be used as a data transfer object in your update method like so.
public class UserController {
#RequestMapping(path="",method=RequestMethod.PUT)
public void update(#RequestBody UpdateUserDTO dto) {
//validate your dto properties and then update your user entity.
userService.save(user);
}
}
Session session = sessionFactory.getCurrentSession();
String newuserId=newuser.getUserId();
session.clear();
User user=userService.readUser(newuserId);
Property1 prop1=user.getProperty1();
List<Property2> prop2=user.getProperty2();
session.clear();
newuser.setProp1(prop1);
newuser.setProp2(prop2);
newuser.save(); //You should go through services and abstraction layers before saving aka it should be in the DAO implementation layer.
Your question needs improvement but try this answer.
You basically save the missing properties in some variables and you append them to your front end User object.
Based on the HQL output it seems like this way gets the user and adds the other properties to it.
Related
Update: The issue seems to be the id that I'm using twice, or in other words, the id from the product entity that I want to use for the productinventory entity. As soon as I generate a new id for the productinventory entity, it seems to work fine. But I want to have the same id for both, since they're the same product.
I have 2 Services:
ProductManagementService (saves a Product entity with product details)
1.) For saving the Product Entity, I implemented an EventHandler that listens to ProductCreatedEvent and saves the product to a mysql database.
ProductInventoryService (saves a ProductInventory entity with stock quantities of product to a certain productId defined in ProductManagementService )
2.) For saving the ProductInventory Entity, I also implemented an EventHandler that listens to ProductInventoryCreatedEvent and saves the product to a mysql database.
What I want to do:
When a new Product is created in ProductManagementService, I want to create a ProductInventory entity in ProductInventoryService directly afterwards and save it to my msql table. The new ProductInventory entity shall have the same id as the Product entity.
For that to accomplish, I created a Saga, which listes to a ProductCreatedEvent and sends a new CreateProductInventoryCommand. As soon as the CreateProductInventoryCommand triggers a ProductInventoryCreatedEvent, the EventHandler as described in 2.) should catch it. Except it doesn't.
The only thing thta gets saved is the Product Entity, so in summary:
1.) works, 2.) doesn't. A ProductInventory Aggregate does get created, but it doesn't get saved since the saving process that is connected to an EventHandler isn't triggered.
I also get an Exception, the application doesn't crash though: Command 'com.myApplication.apicore.command.CreateProductInventoryCommand' resulted in org.axonframework.commandhandling.CommandExecutionException(OUT_OF_RANGE: [AXONIQ-2000] Invalid sequence number 0 for aggregate 3cd71e21-3720-403b-9182-130d61760117, expected 1)
My Saga:
#Saga
#ProcessingGroup("ProductCreationSaga")
public class ProductCreationSaga {
#Autowired
private transient CommandGateway commandGateway;
#StartSaga
#SagaEventHandler(associationProperty = "productId")
public void handle(ProductCreatedEvent event) {
System.out.println("ProductCreationSaga, SagaEventHandler, ProductCreatedEvent");
String productInventoryId = event.productId;
SagaLifecycle.associateWith("productInventoryId", productInventoryId);
//takes ID from product entity and sets all 3 stock attributes to zero
commandGateway.send(new CreateProductInventoryCommand(productInventoryId, 0, 0, 0));
}
#SagaEventHandler(associationProperty = "productInventoryId")
public void handle(ProductInventoryCreatedEvent event) {
System.out.println("ProductCreationSaga, SagaEventHandler, ProductInventoryCreatedEvent");
SagaLifecycle.end();
}
}
The EventHandler that works as intended and saves a Product Entity:
#Component
public class ProductPersistenceService {
#Autowired
private ProductEntityRepository productRepository;
//works as intended
#EventHandler
void on(ProductCreatedEvent event) {
System.out.println("ProductPersistenceService, EventHandler, ProductCreatedEvent");
ProductEntity entity = new ProductEntity(event.productId, event.productName, event.productDescription, event.productPrice);
productRepository.save(entity);
}
#EventHandler
void on(ProductNameChangedEvent event) {
System.out.println("ProductPersistenceService, EventHandler, ProductNameChangedEvent");
ProductEntity existingEntity = productRepository.findById(event.productId).get();
ProductEntity entity = new ProductEntity(event.productId, event.productName, existingEntity.getProductDescription(), existingEntity.getProductPrice());
productRepository.save(entity);
}
}
The EventHandler that should save a ProductInventory Entity, but doesn't:
#Component
public class ProductInventoryPersistenceService {
#Autowired
private ProductInventoryEntityRepository productInventoryRepository;
//doesn't work
#EventHandler
void on(ProductInventoryCreatedEvent event) {
System.out.println("ProductInventoryPersistenceService, EventHandler, ProductInventoryCreatedEvent");
ProductInventoryEntity entity = new ProductInventoryEntity(event.productInventoryId, event.physicalStock, event.reservedStock, event.availableStock);
System.out.println(entity.toString());
productInventoryRepository.save(entity);
}
}
Product-Aggregate:
#Aggregate
public class Product {
#AggregateIdentifier
private String productId;
private String productName;
private String productDescription;
private double productPrice;
public Product() {
}
#CommandHandler
public Product(CreateProductCommand command) {
System.out.println("Product, CommandHandler, CreateProductCommand");
AggregateLifecycle.apply(new ProductCreatedEvent(command.productId, command.productName, command.productDescription, command.productPrice));
}
#EventSourcingHandler
protected void on(ProductCreatedEvent event) {
System.out.println("Product, EventSourcingHandler, ProductCreatedEvent");
this.productId = event.productId;
this.productName = event.productName;
this.productDescription = event.productDescription;
this.productPrice = event.productPrice;
}
}
ProductInventory-Aggregate:
#Aggregate
public class ProductInventory {
#AggregateIdentifier
private String productInventoryId;
private int physicalStock;
private int reservedStock;
private int availableStock;
public ProductInventory() {
}
#CommandHandler
public ProductInventory(CreateProductInventoryCommand command) {
System.out.println("ProductInventory, CommandHandler, CreateProductInventoryCommand");
AggregateLifecycle.apply(new ProductInventoryCreatedEvent(command.productInventoryId, command.physicalStock, command.reservedStock, command.availableStock));
}
#EventSourcingHandler
protected void on(ProductInventoryCreatedEvent event) {
System.out.println("ProductInventory, EventSourcingHandler, ProductInventoryCreatedEvent");
this.productInventoryId = event.productInventoryId;
this.physicalStock = event.physicalStock;
this.reservedStock = event.reservedStock;
this.availableStock = event.availableStock;
}
}
What you are noticing right now is the uniqueness requirement of the [aggregate identifier, sequence number] pair within a given Event Store. This requirement is in place to safe guard you from potential concurrent access on the same aggregate instance, as several events for the same aggregate all need to have a unique overall sequence number. This number is furthermore use to identify the order in which events need to be handled to guarantee the Aggregate is recreated in the same order consistently.
So, you might think this would opt for a "sorry there is no solution in place", but that is luckily not the case. There are roughly three things you can do in this set up:
Life with the fact both aggregates will have unique identifiers.
Use distinct bounded contexts between both applications.
Change the way aggregate identifiers are written.
Option 1 is arguably the most pragmatic and used by the majority. You have however noted the reuse of the identifier is necessary, so I am assuming you have already disregarded this as an option entirely. Regardless, I would try to revisit this approach as using UUIDs per default for each new entity you create can safe you from trouble in the future.
Option 2 would reflect itself with the Bounded Context notion pulled in by DDD. Letting the Product aggregate and ProductInventory aggregate reside in distinct contexts will mean you will have distinct event stores for both. Thus, the uniqueness constraint would be kept, as no single store is containing both aggregate event streams. Whether this approach is feasible however depends on whether both aggregates actually belong to the same context yes/no. If this is the case, you could for example use Axon Server's multi-context support to create two distinct applications.
Option 3 requires a little bit of insight in what Axon does. When it stores an event, it will invoke the toString() method on the #AggregateIdentifier annotated field within the Aggregate. As your #AggregateIdentifier annotated field is a String, you are given the identifier as is. What you could do is have typed identifiers, for which the toString() method doesn't return only the identifier, but it appends the aggregate type to it. Doing so will make the stored aggregateIdentifier unique, whereas from the usage perspective it still seems like you are reusing the identifier.
Which of the three options suits your solution better is hard to deduce from my perspective. What I did do, is order them in most reasonable from my perspective.
Hoping this will help your further #Jan!
I'm using Spring 4.3, and I have a REST Controller that returns a User object to the UI (javascript).
The problem is that I get a User object from the Database (say with Hibernate) that contains a password. I don't want to expose the password by actually returning it. Instead, I want the controller method to put NULL in it before returning it (I could use Optional or other solutions to avoid nulls, but I'm keeping it simple in this question).
public class User {
private String username;
private String password;
//setters and getters
}
#Controller
public class MainController {
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser() {
User user = //getUser
//something to nullify the password?
return user;
}
This question concerns a User and a password for clarity, but I'm looking for a wide solution that would take care of all my data models and the values I don't want them to include in some returns.
Solutions I don't like :)
Disliked solution #1: Remove the password in a private method or a utility class' method or an Adapter class
I don't like this because it makes the code very long. Most controller methods will need their own adaptation of the data.
I prefer something more clean and short.
Disliked solution #2: Use #JsonIgnore annotation
I don't want to bind my data models with Jackson package.
Disliked solution #3: Use a smaller data model class, and blind-copy everything that the smaller can contain
This solution refers to a code such as this:
public class ReturnUser {
private String username;
}
#Controller
public class MainController {
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser() {
User user = //getUser
ReturnUser smaller = copyWhatsInCommon(user, User.class, ReturnUser.class); //sees that there's only username common to both, so copies only it
return smaller;
This also increases the quantity of code, so I don't like it.
Any ideas?
Option 1:
You can add a transformation layer between your controller and the facade (or the service which populates the entity from the database). The transformation layer classes can convert the entities into value objects. The VOs will only contain the minimal information that your view needs. If there are more entities than 1 that you need to transform into value objects, you can also use reflections to read the properties (from a config file or something) that need to be read from the entities and copied to the VOs. However, this is not quite different from the solution 3 in your question that you don't like much. While it serves from performance and security perspective, it does add additional code in form of a transformation layer.
Option 2: An alternate and straightforward option I can propose is read the required attributes from 'User' class and populate them as model attributes.
#RequestMapping(value = "/user/getOne", method = RequestMethod.GET)
public User getOneUser(ModelMap modelMap) {
User user = //getUser
modelMap.addAttribute("userName", user.getName());
modelMap.addAttribute("userEmail", user.getEmail());
...
...
}
}
From experience:
1.) You should not return your business objects from the View layer ie Controller. You see this in many tutorials, but this is poor design.
2.) You should create a response object. This response object will only contain the fields you want to return to the user.
3.) You should instantiate the fields for UserResponse in the constructor with the user object.
Using since you are creating a resposne object, you using the #JsonIgnore annotation doesn't make sense.
While this may be more code, it is a better design with a clear separation of responsibility. The controller only needs to worry about the view object and the business layer never needs to know anything about the view.
Ex
public class UserResponse {
private String firstName;
private String lastName;
public UserResponse(User user){
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
}
...
//The getters
}
In the controller:
return new UserResponse(user);
Why do you want absolutely to return the User as it is represented in your entity?
The service and the controller layers should even not get a User object that contains a password field. So your 1 and 3 solution should be avoided.
In your case returning a view of the User class seems the most relevant way to achieve your need. Just use a DTO
Either you could return the User DTO from a service layer that accesses to the Data Access layer.
Or if you don't have a service layer, you could provide a method in the data access layer that returns a User DTO without the password field.
I am going to offer one more solution. Just for coverage. This is very ugly and not recommended. You can create an object mapper and filter the object:
static ObjectMapper mapper = new ObjectMapper();
public static String filterOutAllExcept(Object obj, String filterName, String... properties) throws YpException {
mapper.registerModule(new Hibernate4Module());
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept(properties);
FilterProvider filterProvider = new SimpleFilterProvider().addFilter(filterName, filter).setFailOnUnknownId(false);
String strValue;
try {
strValue = mapper.writer(filterProvider).writeValueAsString(obj);
} catch (JsonProcessingException e) {
// handle exception
}
return strValue;
}
Then you can call it like:
String filterApplied = ObjectMapperHelper.filterOutAllExcept(user, JsonDTOFilter.SOMEFILTER, "firstName", "lastName");
This will give you a json string with the fields firstName and lastName
My issue is how to organize the code. Let say I have a User class
public class User extends RealmObject {
#PrimaryKey
private String id;
#Required
private String name;
public User() { // per requirement of no args constructor
id = UUID.randomUUID().toString();
}
// Assume getter & setter below...
}
and a Util class is needed to handles the save in an asynchronous manner since RealmObjects cannot have methods other than getter/setter.
public class Util {
public static void save(User user, Realm realm) {
RealmAsyncTask transaction = realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealm(user); // <====== Argument needs to be declared final in parent method's argument!
}
}, null);
}
}
The intention is to put save() in a Util class to prevent spreading similar save code all over the code-base so that every time I wanted to save I would just call it as such:
User u = new User();
u.setName("Uncle Sam");
Util.save(u, Realm.getDefaultInstance());
Not sure if this affects performance at all, but I was just going to save all fields overwriting what was there except for the unique id field every single time.
The problem is that I now need to set the "user" argument as final in the Util.save() method, which means I cannot pass in the object I need to save other than once.
Is there a different way of handling this? Maybe a different pattern? Or am I looking at this all wrong and should go back to SQLite?
Why is it a problem to set public static void save(final User user, Realm realm) ? It just means you cannot reassign the user variable to something else.
That said, the existence of a save() method can be a potential code smell as you then spread the update behaviour across the code base. I would suggest looking into something like the Repository pattern (http://martinfowler.com/eaaCatalog/repository.html) instead.
Realm is actually working on an example showing how you can combine the Model-View-Presenter architecture with a Repository to encapsulate updates which is a good pattern for what you are trying to do here. You can see the code for it here: https://github.com/realm/realm-java/pull/1960
I have a situation in my requirements I would like to see if someone has a strong opinion about it.
The project I'm working on requires that, given a Customer, once the Customer adds a Product to a Cart, if the Cart is not present, the Cart has to be created. At the moment, the aggregate is the Customer and it contains the Cart that contains the Product. Because this system is kind of a side one that supports the real e-commerce project, the creation of the Customer and the Cart is taken for granted once an "AddProductCommand" is received. In that situation, both Customer and Cart have to be created if they are not there already.
My current implementation creates the Customer at the application service if it doesn't exist. Once created, I pass the AddProductRequest using customer.addProduct(addProductRequest). AddProductRequest contains the Cart id and the Product id. The problem comes here. Once in the Customer aggregate, if the Cart is not there, I have to create it. So basically, I don't have an addCart in customer with a Cart entity that I call first to then call addProduct. I need to create the Cart if it's not there from inside the Customer aggregate and then add the Product to it. And to do this, I don't create any factory as I don't want to have a static method that complicates testing and I can't just create a new factory inside the aggregate either. I just create the Cart entity using the new operator in a protected method that I override when testing to verify what I'm doing there.
So my question is, is this a valid approach? In my head, to add a Product to a Cart, the Cart should be added first to the Customer and fail if it's not there. To do it this way I would need to add logic to the application service where first I would ask the Customer if he has a Cart with that id, create it otherwise, and add it to Customer before adding the Product. I could add a domain service that is given this request but then I would need to inject the factory to create the Cart into it, when I've read in several places that a domain service shouldn't be injected any factory, that should be the work of the application service.
I could do it that way but the project will get more complicated in the future as there will be yet another layer where a Product could be added a list of Vouchers having to also create Customer, Cart and Product if they are not there when the AddVoucherCommand is consumed. In this situation, if I don't want to create the entities inside the model, I would need to check at the application/domain service whether each aggregate or entity has the necessary entity inside it, which I don't think is very DDD friendly, or just keep doing what I'm doing at the moment. This is, each aggregate/entity is in charge of create the necessary entity before calling the addXXXX method on it.
Some simplified code to explain what I'm doing at the moment and what I'm going to have to do in the future:
public class CustomerService {
public void addVoucher(AddVoucherRequest addVoucherRequest) {
Customer customer = customerRepo.load(customerId);
customer.addVoucher(addVoucherRequest);
customerRepo.save(customer);
}
}
public class Customer() {
public void addVoucher(AddVoucherRequest addVoucherRequest) {
Cart cart = getOrCreateIfAbsent(addVoucherRequest.getCartId());
cart.addVoucher(addProductRequest);
}
private Cart getOrCreateIfAbsent(long cartId){
Optional<Cart> cart = carts.stream().filter(cart -> cart.getId() == cartId).findFirst();
return cart.orElseGet(() -> {
Cart newCart = createCart(cartId);
carts.add(newCart);
return newCart;
}
}
protected Cart createCart(long cartId) {
return new Cart(cartId);
}
}
public class Cart() {
public void addVoucher(AddVoucherRequest addVoucherRequest) {
Product product = getOrCreateIfAbsent(addVoucherRequest.getProductId());
product.addVoucher(addVoucherRequest);
}
private void getOrCreateIfAbsent(long productId) {
Optional<Product> product = products.stream().filter(product -> product.getId() == productId).findFirst();
return product.orElseGet(() -> {
Product newProduct = createProduct(productId);
products.add(newProduct );
return newProduct ;
}
}
protected Product createProduct(long productId) {
return new Product(productId);
}
}
Any suggestions?
Thanks!
Choosing to wait for a Customer to order something to create him/her in the new system rather than importing all Customers from the legacy system upfront is a purely technical decision, it has nothing to do with your domain IMO.
Therefore, it shouldn't affect the way you design your domain objects in any way - as I understand it, getOrCreateIfAbsent() should be a behavior in some kind of application service, not in one of your entities.
I'm trying to write an application for the google app engine using Objectify and am having some trouble. I'm new to noSQL datastores so it's probably a conceptual problem.
I have an entity called a message, and each message has a from User - the user who created the message.
#Entity
public class Message {
#Index private Key<User> fromUserKey;
#IgnoreSave private User fromUser;
Annoyingly, I have to have both a User and a Key field in the message. JSON needs the User object to populate the response with useful fields, and the google app engine needs the Key to be able to store the reference to the user. The #IgnoreSave annotation is used to stop Objectify asking the google app engine to try to store the User object (which will fail).
When fetching messages, the from user key is populated, but the from User object is not. Here's what the DAO code looks like for my "getMessages" operation:
public static List<Message> getSentMessages(long userId) {
List<Message> result;
result= ofy().load().type(Message.class).filter("from", Key.create(User.class, userId)).limit(1000).list();
return result;
}
But the fromUser object is not populated on each Message, only the fromUserKey. How do I get the actual User object populated in the response? I need to access such fields as forename, surname, etc - not just the ID of the User. I could get the from User from the DB, loop through the results, then call setFromUSer on each message, but it's ugly. And it also causes a ConcurrentModificationException...
I'm sure I'm doing something wrong here, but I can't work out what.
What you can do is have a property Ref<User> on the Message entity and annotate it with '#Parent'. This means that each Message entity will become part of the user's entity group.
The Ref<?> works like a key but allows you to directly access the actual entity object; that way you can easily get the forename, surname etc.
Change your class as follows:
#Entity
#Cache
public class Message
{
#Id Long id;
#Load #Parent private Ref<User> user;
public User getUser() { return this.user.get(); }
public void setUser(User value) { this.user = Ref.Create(value); }
}
Having done that, you will be able to perform ancestor queries to retrieve all the message entities associated with a particular user:
public static List<Message> getSentMessages(long userId)
{
User parent = ofy().load().type(User.class).id(userId).now();
List<Message> results = ofy().load().type(Message.class).ancestor(parent).limit(1000).list();
return results;
}
You should now be able to do what you wanted, and hopefully not get any more errors.