Skip to content

Instantly share code, notes, and snippets.

@GordPavel
Last active September 25, 2023 14:05
Show Gist options
  • Select an option

  • Save GordPavel/bba52936848cd97df5952837b7fa0875 to your computer and use it in GitHub Desktop.

Select an option

Save GordPavel/bba52936848cd97df5952837b7fa0875 to your computer and use it in GitHub Desktop.
// package my.code.cache.dao
public class CacheEntity {
String id;
String jsonData;
}
public interface CacheEntityRepository {
Optional<CacheEntity> findById(String id);
CacheEntity save(CacheEntity entity);
}
// package my.code.cache.dao.jpa
interface JpaCacheEntityRepository extends JpaRepository<CacheEntity, String>, CacheEntityRepository {}
// package my.code.cache
public class Cache<T> {
String id;
T data;
private Cache(String id, T data) {
this.id = id;
this.data = data;
}
public String getId() {
return id;
}
public T getData() {
return data;
}
}
public abstract class CacheService<T> {
protected abstract Optional<Cache<T>> fetchFromCache(String id);
protected abstract void putToCache(Cache<T> cache);
}
public class CacheServiceMapper {
private final ObjectMapper objectMapper;
public CacheServiceMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
<T> Cache<T> fromEntity(CacheEntity entity, Class<T> dataType) {
try {
return new Cache<>(entity.id, objectMapper.readValue(entity.jsonData, dataType));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
CacheEntity toEntity(Cache<?> cache) {
final var cacheEntity = new CacheEntity();
cacheEntity.id = cache.id;
try {
cacheEntity.jsonData = objectMapper.writeValueAsString(cache.data);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return cacheEntity;
}
}
public abstract class AbstractCacheService<T, K> extends CacheService<T> {
private final CacheEntityRepository cacheEntityRepository;
private final CacheServiceMapper cacheServiceMapper;
AbstractCacheService(
CacheEntityRepository jpaCacheEntityRepository,
CacheServiceMapper cacheServiceMapper
) {
this.cacheEntityRepository = jpaCacheEntityRepository;
this.cacheServiceMapper = cacheServiceMapper;
}
@Override
protected Optional<Cache<T>> fetchFromCache(String id) {
return cacheEntityRepository
.findById(id)
.map(entity -> cacheServiceMapper.fromEntity(entity, dataClass()));
}
@Override
protected void putToCache(Cache<T> cache) {
cacheEntityRepository.save(cacheServiceMapper.toEntity(cache));
}
protected abstract Class<T> dataClass();
}
// package my.code.party
class Party {
UUID id;
public UUID getId() {
return id;
}
}
// package my.code.party.cache
abstract class PartyCache extends AbstractCacheService<Party, UUID> {
PartyCache(CacheEntityRepository jpaCacheEntityRepository, CacheServiceMapper cacheServiceMapper) {
super(jpaCacheEntityRepository, cacheServiceMapper);
}
@Override
protected Class<Party> dataClass() {
return Party.class;
}
public Optional<Party> fetchPartyFromCache(UUID id) {
return super.fetchFromCache(id.toString()).map(Cache::getData);
}
public void putPartyToCache(Party party) {
super.putToCache(new Cache<>(party.getId().toString(), party));
}
}
class PostgresPartyCache extends PartyCache {
PostgresPartyCache(JpaCacheEntityRepository jpaCacheEntityRepository, CacheServiceMapper cacheServiceMapper) {
super(jpaCacheEntityRepository, cacheServiceMapper);
}
}
// package my.code.party.dao.jpa
static class PartyEntity {
UUID id;
}
interface JpaPartyEntityRepository extends JpaRepository<PartyEntity, UUID> {}
interface PartyDaoMapper {
Party fromEntity(PartyEntity party);
PartyEntity toEntity(Party party);
}
// package my.code.party.dao
class PartyDao {
private final JpaPartyEntityRepository partyEntityRepository;
private final PartyCache partyCache;
private final PartyDaoMapper partyDaoMapper;
PartyDao(
JpaPartyEntityRepository partyEntityRepository,
PartyCache partyCache,
PartyDaoMapper partyDaoMapper
) {
this.partyEntityRepository = partyEntityRepository;
this.partyCache = partyCache;
this.partyDaoMapper = partyDaoMapper;
}
Optional<Party> findPartyById(UUID id) {
final var cachedParty = partyCache.fetchPartyFromCache(id);
if (cachedParty.isPresent()) {
return cachedParty;
}
final var party = partyEntityRepository.findById(id).map(partyDaoMapper::fromEntity);
if (party.isPresent()) {
partyCache.putPartyToCache(party.get());
return party;
}
return Optional.empty();
}
void saveParty(Party party) {
partyCache.putPartyToCache(party);
partyEntityRepository.save(partyDaoMapper.toEntity(party));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment