Spring cacheable annotation with multiple key - spring

I have 2 ways to lookup a customer record (code below), customerGuid and customerId are 2 different fields in Customer object.
Suppose that i lookup customer by customerId once, is there a way for me to lookup customer by guid directly from cache without querying backend, Assuming both the methods return type is Customer.
public class CustomerLookup {
#Cacheable("customerCache")
public Customer getCustomerByGuid(final String customerGuid) {
// some implementation here...
}
#Cacheable("customerCache")
public Customer getCustomerByCustId(final String customerId) {
// some implementation here...
}
}

You can add a 2nd parameter to one method which will only serve as cache key. Example use customerId as key and proceed like this:
#Service
public class CustomerLookup {
#Autowired
#Lazy
private CustomerLookup self;
#CachePut("customerCache", key="#customerId")
public Customer getCustomerByGuid(final String customerGuid, String customerId) {
Customer customer = self.getCustomerByCustId(final String customerId);
//......
}
}
Note the self-injection of CustomerLookup if you don't do that the cache won't work when you call the getCustomerByCustId(final String customerId) method in getCustomerByGuid. Also note the #CachePut instead of #Cacheable on getCustomerByGuid, with this you are sure that this method will be called everytime.

Related

Spring HATEOAS recursive representation model processors?

I have a question concerning the representation model processors of Spring HATEOAS. We are experimenting to process models before serializing them to the client. Our use case is to enrich the imageUrl field of UserModel objects at runtime, as we have to build the URL based on values from a config bean (AWS S3 bucket URL differs for DEV / PROD setup).
#Data
public class UserModel {
// ...
private String imageUrl;
}
Therefore, we create a UserProcessor to implement this:
public class UserProcessor implements RepresentationModelProcessor<EntityModel<UserModel>> {
private final ConfigAccessor configAccessor;
public UserProcessor(ConfigAccessor configAccessor) {
this.configAccessor = configAccessor;
}
#Override
public EntityModel<UserModel> process(EntityModel<UserModel> model) {
if (model.getContent() != null)
// do the enrichment and set "imageUrl" field
}
return model;
}
}
This works perfectly if we have a controller method like this:
#ResponseBody
#GetMapping("/me")
public EntityModel<UserModel> getCurrentUser(#AuthenticationPrincipal Principal principal) {
UserModel user = ... // get user model
return EntityModel.of(user);
}
However, we are struggling now with the enrichment whenever a UserModel is referenced in another model class, e.g., the BookModel:
#Data
public class BookModel {
private String isbn;
// ...
private EntityModel<UserModel> user; // or "private UserModel user;"
}
A controller method returning type EntityModel<BookModel> only applies the processor for its type, but not for types that are referenced. It seems the processors are not applied recursively.
Is this intentional or are we doing something wrong?
Thanks for any input and help,
Michael
I encountered the same issue and I resolved it by manually assembling resources, in your case that would be implementing RepresentationModelAssembler of the BookModel and then manually invoking the processor on the userModel object that is inside the book.
Make the outer resource a representation model
First consider the BookModel to extend RepresentationModel so that you can manually add links and assemble inner resources (which you would like for the EntityModel<UserModel> object)
#Data
public class BookModel extends RepresentationModel<BookModel> {...}
Write a model assembler
Now write the assembler that takes your book entity and transforms it into a representation model or a collection of these models. You will implement here what EntityModel.of(...) does for you automagically.
#Component
public class BookModelAssembler implements RepresentationModelAssembler<Book, BookModel> {
#Autowired
private UserProcessor userProcessor;
#Override
public BookModel toModel(Book entity) {
var bookModel = new BookModel(entity) // map fields from entity to model
// Transform the user entity to an entity model of user
var user = entity.getUser();
EntityModel<UserModel> userModel = EntityModel.of(user);
userModel = userProcessor.process(userModel);
bookModel.setUserModel(userModel);
return bookModel;
}
}
I might be going out on a limb but I suppose the reason for this is that the processors get invoked when an MVC endpoint returns a type that has a registered processor, which in the case of embedded types is not invoked. My reasoning is based on the docs for RepresentationModelProcessor, which states that processor processes representation models returned from Spring MVC controllers.

resolveContextualObject and getConversationId in custom Spring scope

I am wondering what is the purpose of org.springframework.beans.factory.config.Scope.resolveContextualObject(String key) and org.springframework.beans.factory.config.Scope.getConversationId()?
From the javadoc:
Object resolveContextualObject(String key)
Resolve the contextual object for the given key, if any. E.g. the HttpServletRequest object for key "request".
String getConversationId()
Return the conversation ID for the current underlying scope, if any.
The exact meaning of the conversation ID depends on the underlying storage mechanism. In the case of session-scoped objects, the conversation ID would typically be equal to (or derived from) the session ID; in the case of a custom conversation that sits within the overall session, the specific ID for the current conversation would be appropriate.
This description doesn't tell me much.
Could you give me some examples which demonstrate how to make use of these methods?
My observation is that resolveContextualObject(String key) looks like a code smell, where where a Scope can expose some internal object.
Having:
public class MyCustomScope implements Scope {
private Pair<String, String> myPair;
#Override
public Object resolveContextualObject(String key) {
if ("myKey".equals(key)) return myPair;
return null;
}
// ...
}
#Configuration
public class RegisterMyScopeConfig {
#Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor() {
return beanFactory -> beanFactory.registerScope(
"mycustomscope", new MyCustomScope());
}
}
Then you can:
#Scope("mycustomscope")
#Component
class MyComponent {
#Value("#{myKey.first}")
private String firstOfMyPair;
// or
#Value("#{myKey}")
private Pair<String,String> myPair;
}
Of course the way how you resolved object which matches key, might be fancier ;).
For example, in GenericScope it looks like that:
#Override
public Object resolveContextualObject(String key) {
Expression expression = parseExpression(key);
return expression.getValue(this.evaluationContext, this.beanFactory);
}

From request object to the database

I have an app with an AngularJS front-end and a Spring MVC back-end. I'm having some trouble with converting/mapping request objects to domain/dto objects.
On one page you can add a new order to the system, the POST payload would look something like this:
{
memo: "This is some extra info for order",
orderLines: [{productId:3, quantity:4}, {productId:2, quantity:5}, {productId:1, quantity:4}],
shippingDate: "2014-10-08T19:16:19.947Z",
warehouseId: 2
}
The Spring MVC controller method looks like this:
#RequestMapping(value = "/order", method = RequestMethod.POST)
public ResponseEntity<Void> addOrder(#RequestBody #Valid OrderRequest orderRequest, UriComponentsBuilder b) throws Exception {
// the magic
}
Where OrderRequest is filled with the values of the POST request, the OrderRequest and OrderLineRequest look like this:
public class OrderRequest {
private Long id;
private Date shippingDate;
private String memo;
private List<OrderLineRequest> orderLines;
private Long warehouseId;
public OrderRequest() {
}
// getters and setters ommitted
}
public class OrderLineRequest {
private Long id;
private String productCode;
private int quantity;
public OrderLineRequest() {
}
}
My question now is, in order to save an Order object with orderService.add(order) I need to construct the Order object based on the values that were sent in the request. Where/how do I do this?
OPTION 1
The OrderRequest class could have a makeOrder() method with just returns an Order object like so:
public Order makeOrder() {
Order order = new Order();
order.setMemo(this.memo);
order.setShippingDate(this.shippingDate);
...
}
Then I'd have to map the OrderLineRequest which could have their own makeOrderLine method:
public OrderLine makeOrderLine() {
OrderLine orderLine = new OrderLine();
orderLine.setQuantity = this.quantity;
...what to do with only the productId?
}
As you can see I can set the quantity but in the request I only received the productId, but in the database I save the productCode, productName as well, so I need that info from the database, but I don't want to make a database call from the Request object...I also don't want to half of the mapping in the request object and the rest of the mapping in the controller where I do have access to the services.
OPTION 2
I can use Dozer to do the mapping for me, but that would mean injecting the services into the Dozer custom converters which seem equally unclean to me...
OPTION 3
I pass the OrderRequest object to the service layer and let the service layer handle it, but my question would remain, how exactly would the service layer convert it, say you have the method addOrder like this:
public void addOrder(OrderRequest orderRequest) {
}
Would you call another service to convert from one to the other as I don't really want this conversion in a business logic method?
Any help would be appreciated
use the #RequestBody to map your jsonObject that is send with the request , to a DTO .
please refer to the following tutorial .
hope that helps .
and please ask if there is something not clear .

OpenEntityManagerInView is not working with JSF

I have created sample project using JSF+Spring+JPA.
I have 2 entities Customer and Order where customer can have more than one order so mapping between Customer and Order is #OneToMany.
Customer Class is as below
#Entity
#NamedQueries
(
{
#NamedQuery(name=Contact.QUERY_FIND_ALL, query="FROM Contact"),
}
)
public class Customer
{
public final static String QUERY_FIND_ALL="findAll";
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private List<Order> orders;
public List<Order> getOrders()
{
return orders;
}
public void setOrders(List<Order> orders)
{
this.orders = orders;
}
}
My View works like below
1st Case:
We load all cutomer and display them on screen with and arrow in
front of each record this happens in one request.
now when end-user click on arrow we want to display all order of
that Customer.
but i am getting Lazy load exception even though i am using OpenEntityManagerInView.
2nd Case:
If I load both Customer and Order in one request it work fine.
is there somthing like that if we load parent in one request we cant load its lazy association in second request?
why its not working in 1st case and working in second case?
and
more important what is the other solution to archive it?
When you load customer on your data access layer class (e.g CustomerDAO) you have to get at least one of each child property to bypass lazy proxy, maybe it would look like this
public class CustomerDAO{
public Customer getCustomer(String custId){
Customer cust = //your method to retrieve customer
List<Order> orders = cust.getOrders();
for(Order ord:orders){
ord.getOrderName(); // you have to get at least one of each child property to bypass lazy proxy
}
}
}
Hope it would help

Validating a domain object for persistence

In the system I'm currently working on, I'm following SRP (I think!) by separating the validation of domain business rules vs persistence constraints. Let's employ the overused customer example. Say a customer must have a valid zip code, street address and name to satisfy the system's business rules. Let's further say that the customer's selected user name must be unique across all customers, which I define as a persistence constraint. Please consider the following "not ready for production" pseudo code:
public interface IPersistenceValidator<T>
{
bool IsValidForPersistence(T domainObj, IList<ValidationError> validationErrors);
}
public interface IValidatable
{
bool IsValid(IList<ValidationError> validationErrors);
}
public class Customer : IValidatable
{
public bool IsValid(IList<ValidationError> validationErrors)
{
//check for business rule compliance
}
}
public class CustomerDao : IPersistenceValidator<Customer>
{
public bool IsValidForPersistence(Customer domainObj, IList<ValidationError> validationErrors)
{
//check for persistence constraint compliance (user name is unique)
}
public bool SaveCustomer(Customer customer)
{
//save customer
}
}
The classes defined above might get wired up into a service class as follows:
public class SaveCustomerService
{
private CustomerDao _customerDao;
public SaveCustomerService(CustomerDao customerDao)
{
_customerDao = customerDao;
}
public bool SaveCustomer(Customer customer)
{
IList<ValidationError> validationErrors = new List<ValidationError>();
if (customer.IsValid(validationErrors))
{
if (_customerDao.IsValidForPersistence(customer, validationErrors))
{
return _customerDao.SaveCustomer(customer);
}
else
{
return false;
}
}
else
{
return false;
}
}
}
My primary concern with this approach is that future consumers of CustomerDao must know to call IsValidForPersistence() before SaveCustomer(), otherwise invalid data gets persisted. I could create DB constraints to guard against this at the SQL levels, but that feels like a kludge.
It seems like IsValidForPersistence() should be moved into CustomerDao.SaveCustomer() but then I have to refactor the signature of SaveCustomer() to include references to the ValidationErrors class. Before I dive into that big of a refactoring, I wanted to get some feedback from others on common/preffered patterns for dealing with these issues.
Thanks
first check HERE if you want to solve your validation problem like;
public class Address {
#NotNull private String line1;
private String line2;
private String zip;
private String state;
#Length(max = 20)
#NotNull
private String country;
#Range(min = -2, max = 50, message = "Floor out of range")
public int floor;
...
}
anyway you must check username in database. You can customize your validation (like go and check DB for that is unique). Look at another links to detail.
Check hibernate validator
Check Using the Validator framework from jboss
You can read Validation In The Domain Layer partI, partII, this is not java but logic is important.

Resources