Feature Enrichment with Spring Data Redis and Lettuce

Lettuce by far is the best Redis client out there for Java. In the java world, Annotations and Mappings are pretty popular. I build services using these concepts before however they were always under the service boundaries, never as shared libraries in order to avoid coupling. So today I record a video showing how we can use this feature and also extend the functionality to add custom enriched behavior.  We will be using Spring Boot 2, Spring Data Redis, and Lettuce as redis Client. We also will need to have redis running either as standalone / cluster or running on docker. We will create custom annotations in order to describe the behavior we want. I need to say that some people love and other people hate annotations, I have mixed feelings. Often for those that don't like it - check this out. Besides that, let's take a look. So Let's get started.


Video



Code

Model

Our model is pretty simple. Simple Person POJO with Getters/Setters, toString, equals/hashCode all generated by Idea. You can see there is a custom annotation called UpperCase. The idea is to add custom features enrichment and make sure some fields are stored in the Upper case.

@RedisHash
public class Person {
private String id;
@UpperCase
private String name;
@UpperCase
private String mail;
public Person() {}
public Person(String name, String id, String mail) {
this.name = name;
this.id = id;
this.mail = mail;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", mail='" + mail + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(id, person.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
view raw Person.java hosted with ❤ by GitHub


Annotation

Now let's look at the annotation.

@Documented
@Retention(value = RetentionPolicy.RUNTIME)
public @interface UpperCase {}
view raw UpperCase.java hosted with ❤ by GitHub


Custom Repository

Here is where the magic happens. I wrapped all CurdRepository operations and I'm delegating to the proper CrudRepository implementation at the end of the day. However I', also I have a reflection code that adds the feature enrichment I want based on the existence of the UpperCase annotation at the Entity fields.

@Repository
public class RedisPersonRepository<T> {
@Autowired
private CrudRepository<T, String> repo;
public T save(T entity) {
try{
for(Field f : entity.getClass().getDeclaredFields()){
if (f.isAnnotationPresent(UpperCase.class)){
Method getter = entity.getClass().getMethod("get" + toCamelCase(f.getName()));
Method setter = entity.getClass().getMethod("set" + toCamelCase(f.getName()), f.getType() );
Object value = getter.invoke(entity);
if (null!=value)
setter.invoke(entity,value.toString().toUpperCase());
}
}
return repo.save(entity);
}catch (Exception e){
throw new RuntimeException(e);
}
}
private String toCamelCase(String name){
return (name.charAt(0) + "").toUpperCase() + name.substring(1);
}
public Iterable<T> saveAll(Iterable<T> entities) {
return repo.saveAll(entities);
}
public Optional<T> findById(String s) {
return repo.findById(s);
}
public boolean existsById(String s) {
return repo.existsById(s);
}
public Iterable<T> findAll() {
return repo.findAll();
}
public Iterable<T> findAllById(Iterable<String> strings) {
return repo.findAllById(strings);
}
public long count() {
return repo.count();
}
public void deleteById(String s) {
repo.deleteById(s);
}
public void delete(T entity) {
repo.delete(entity);
}
public void deleteAll(Iterable<? extends T> entities) {
repo.deleteAll(entities);
}
public void deleteAll() {
repo.deleteAll();
}
}


The complete code is here.

Cheers,
Diego Pacheco

Popular posts from this blog

Having fun with Zig Language

C Unit Testing with Check

Cool Retro Terminal