0

Let's say I have this Util class:

public class Resources {
 public static List<Product> PRODUCTS;
 public static List<Customer> CUSTOMERS;
 public static Product getProductById(int id) {
 for (Product product : PRODUCTS) {
 if (product.getIdProduct() == id) {
 return product;
 }
 }
 return null;
 }
 public static Customer getCustomerById(int id) {
 for (Customer customer : CUSTOMERS) {
 if (customer.getId() == id) {
 return customer;
 }
 }
 return null;
 }

}

  • This serves as caching mechanism for entities Product and Customer, which were retrieved from database. So whenever I need to work with Customer (or Product) first I take a look at the Resources.CUSTOMERS (PRODUCTS) if it's there I save the time and don't have to call server. Not sure if Spring can handle it on itself, so I did it that way.
  • My issue is huge amount of boiler plate code here. If I will have 10, 20,... entities I will have to write 10, 20,... getter method and all of them will do pretty same thing. What is the best acceptable solution respecting some best practices?
asked Jan 3, 2023 at 0:20

2 Answers 2

1

You could use a generic method to retrieve an entity by it's ID. Just introduce a type parameter to the method, which represents the type of entity being retrieved.

Then you can use a single method for your getCustomerById(int id) and getProductById(int id) methods:

public class Resources {
public static <T> T getEntityById(List<T> entities, int id, Function<T, Integer> idExtractor) {
 for (T entity : entities) {
 if (idExtractor.apply(entity) == id) {
 return entity;
 }
 }
 return null;
 }
}

You can then call this method to retrieve a Product or Customer entity like this:

Product product = Resources.getEntityById(PRODUCTS, productId, Product::getId);
Customer customer = Resources.getEntityById(CUSTOMERS, customerId, Customer::getId);

This will make it a lot easier adding support for additional entity types in the future.

answered Jan 3, 2023 at 0:51
Sign up to request clarification or add additional context in comments.

Comments

1

Not sure if Spring can handle it on itself

Most likely, it can. For instance, if you access the database with JPA, JPA caching does exactly this.

Configuring that is a bit of work, because you need to specify eviction policies (i.e. what happens if memory runs out). The implementations also take care of thread safety, and many offer storage on disk or replicating storage in a cluster.

Of course, you can reinvent the wheel. It might even make sense if the wheel you need is much simpler, for instance because you never update the cache once constructed (so thread safety is trivial) and the entire table fits into memory (so you don't need to evict).

To do that, I'd first choose a more appropriate data structure that offers efficient lookup by key, i.e. a Map. And then I would combine all these redundant methods into one:

class Resources {
 static Map<Class<?>, Map<Integer, ?>> CACHE = new HashMap<>(); 
 // ... or something thread safe, if you intend to update the cache later
 public getEntity<E>(Class<E> entityClass, int id) {
 return entityClass.cast(CACHE.get(entityClass).get(id));
 }
}

Usage

 Product p = Resources.getEntity(Product.class, 42);
 Customer c = Resources.getEntity(Customer.class, 36);
answered Jan 3, 2023 at 1:50

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.