How to use RedisTemplate to store different datatypes - redis

I am using Spring RedisTemplate to deal with operations related to Redis. Will I be able to store two datatypes. For example I want to store Key,String as well as Key,Integer. How to acheive this?

Have you read http://docs.spring.io/spring-data/redis/docs/current/reference/html/redis.html ?
Altering a bit from docs, untested:
public class Example {
// inject the actual template
#Autowired
private RedisTemplate<String, String> template;
// inject the template as ValueOperations
#Resource(name="redisTemplate")
private ValueOperations<String, Integer> intOp;
#Resource(name="redisTemplate")
private ValueOperations<String, String> stringOp;
public void sampleKeySetting() {
intOp.set('my_int_value', 10);
stringOp.set('my_string_value', 'good!');
}
}
There are XXXXOperations for other data structures too: check http://docs.spring.io/spring-data/data-keyvalue/docs/current/api/org/springframework/data/keyvalue/redis/core/RedisOperations.html

Related

Manually convert JSON to Object using Spring Data Rest

Let's say I have the following entity:
public class Employee {
private String name;
private Company company
}
And I have a String with the content below:
{
"name":"Joe",
"company": "http://localhost/companies/23"
}
Spring Data Rest is capable of converting this JSON to an Employee object out of the box, but to how convert it manually?
OK. I think I understand the problem now. Of course SDR has to have an ObjectMapper which is capable to convert the incoming JSON into an entity (including hateoas links), but it seems that's NOT the default ObjectMapper and it's not even exported as a Bean.
So I made some reverse-engineering and I think I've found what you need. Fortunately the ObjectMapper which is used internally has a public getter in the RepositoryRestMvcConfiguration class, so it can be used easily:
/**
* The Jackson {#link ObjectMapper} used internally.
*
* #return
*/
public ObjectMapper objectMapper() {
return mapper.get();
}
I think the following code will work:
#Autowired
RepositoryRestMvcConfiguration rrmc;
private <T> T readValue(String json, Class<T> type)
throws IOException, JsonParseException, JsonMappingException {
return rrmc.objectMapper().readValue(json, type);
}
#Aurowired
private final RepositoryInvokerFactory repositoryInvokerFactory;
private Object loadPropertyValue(Class<?> type, String href) {
String id = href.substring(href.lastIndexOf('/') + 1);
RepositoryInvoker invoker = repositoryInvokerFactory.getInvokerFor(type);
return invoker.invokeFindById(id).orElse(null);
}

Spring Data Rest ID conversion using HashIDs

We have a concern exposing internal IDs to the outside world. Therefore I'm thinking about using a hashing mechanism (current choice is hashids) to hash our IDs.
I tried to use a #JsonSerializer and #JsonDeserializer mapping on the Entities ID field. But this only takes effect when including the ID in the body, and has no impact on the IDs in the URL paths.
Is there a possibility to do this, e.g. something like an ID Translation SPI?
The only thing I can think of is to create a request filter that would take the request with encoded ID in URL, then decode the ID and redirect to an URL with decoded ID.
What you need is working "right from the box" in Spring Data REST by customizing item resource URIs:
#Configuration
public class RestConfigurer extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.withEntityLookup().forRepository(ModelRepo.class, model -> HashIdUtil.encode(model.getId()), ModelRepo::findByEncodedId);
super.configureRepositoryRestConfiguration(config);
}
}
public interface ModelRepo extends JpaRepository<Model, Long> {
default Model findByEncodedId(String encodedId) {
return getById(HashIdUtil.decode(encodedId));
}
Model getById(Long id);
}
public class HashIdUtil {
private static final Hashids HASHIDS = new Hashids("salt", 8);
public static String encode(Long source) {
return HASHIDS.encode(source);
}
public static Long decode(String source) {
return HASHIDS.decode(source)[0];
}
}
Unfortunately, due to the bug (I suppose), PUT/PATCH-ing entities does not work in Spring Boot 2+, unlike the previous version of SB (1.5+) where it works as expected.
See my demo: sdr-hashids-demo
You could try using a converter.
#Component
#AllArgsConstructor
public class HashIdConverter implements Converter<String, Long> {
private final HashidsUtil hashidsUtil;
#Override
public Long convert(#NonNull String source) {
return hashidsUtil.decodeId(source);
}
}
Using it the way I just showed you is a bit unsafe, but it can do the work quite well if you are careful enough

How do I load data from a Hadoop Avro source into ActivePivot store?

How do I load data from a Hadoop Avro source into ActivePivot store?
Look in the ActivePivot Sandbox project you should have access to and check out where channels are use to persist data to datastores.
Suppose you have class that should be posted to the cube.
public class PostVectorFact {
private final LocalDate date;
//other fields
//getters, equals, hashCode
}
In your spring configuration you need to define message chanell
#Autowired
protected IDatastore datastore;
#Autowired
protected KeepArbitraryEpochPolicy epochPolicy;
#Autowired
protected LocationHelper locationHelper;
public IMessageChannel<String, Object> returnsRealTimeChannel() {
return pojoMessageChannelFactory().createChannel("RealTimeReturns", DataStoreConstants.RETURNS_STORE, tuplePublisher());
}
#Bean
ITuplePublisher<String> tuplePublisher() {
return new VersionCheckingTuplePublisher(datastore, DataStoreConstants.RETURNS_STORE, DataStoreConstants.LATEST_RETURNS_STORE, 2L, epochPolicy, locationHelper);
}
#Bean
public CubeReturnsFactPublisher cubeReturnsFactPublisher() {
return new CubeReturnsFactPublisher(returnsRealTimeChannel());
}
And the publisher class itself:
public class CubeReturnsFactPublisher {
IMessageChannel<String, Object> messageChannel;
public CubeReturnsFactPublisher(IMessageChannel<String, Object> messageChannel) {
super();
this.messageChannel = messageChannel;
}
public void publish(List<ReturnVectorFact> facts) {
messageChannel.sendMessage("", facts);
}
}
The way how you publish your data:
cubeReturnsFactPublisher.publish(Collections.singletonList(new PostVectorFact(...)));

Spring Data + Redis with Auto increment Key

I am trying to do Spring data CRUD Operation with Redis but mainly I need to store the auto increment key in Redis.
I have tried the simple CRUD operation for SpringData with Redis but there is no auto increment key feature.
How can I achieve this?
If you are using spring data redis repository, you can annotate the field with org.springframework.data.annotation.Id for which value needs to be auto generated and a #RedisHash annotation on its class.
#RedisHash("persons")
public class Person {
#Id String id;
String firstname;
String lastname;
Address address;
}
To now actually have a component responsible for storage and retrieval you need to define a repository interface.
public interface PersonRepository extends CrudRepository<Person, String> {
}
#Configuration
#EnableRedisRepositories
public class ApplicationConfig {
#Bean
public RedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
#Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
return template;
}
}
Given the setup above you can go on and inject PersonRepository into your components.
#Autowired PersonRepository repo;
public void basicCrudOperations() {
Person rand = new Person("rand", "al'thor");
rand.setAddress(new Address("emond's field", "andor"));
repo.save(rand); //1
repo.findOne(rand.getId()); //2
repo.count(); //3
repo.delete(rand); //4
}
Generates a new id if current value is null or reuses an already set id value and stores properties of type Person inside the Redis Hash with key with pattern keyspace:id in this case eg. persons:5d67b7e1-8640-4475-beeb-c666fab4c0e5.
Uses the provided id to retrieve the object stored at keyspace:id.
Counts the total number of entities available within the keyspace persons defined by #RedisHash on Person.
Removes the key for the given object from Redis.
Reference: http://docs.spring.io/spring-data/redis/docs/current/reference/html/

StructureMap - Inject Conditional Class

I have 1 interface named IProcessor having multiple implementations like ABCProcessor, PQRProcessor.
I want to make use of specific processor based on external parameters. How can I achive the same using StructureMap.
I am looking at named instances for the same.
You could use a factory pattern:
public interface IProcessorFactory
{
IProcessor Create(int dropDownValue);
}
public class ProcessorFactory : IProcessorFactory
{
private readonly IContainer _container;
public ProcessorFactory(IContainer container)
{
_container = container;
}
public IProcessor Create()
{
if(//your condition)
return _container.GetInstance<ABCProcessor>();
_container.GetInstance<PQRProcessor>();
}
}
(or simply inject the required dependencies instead of the container)
and then simply
private readonly IProcessorFactory _processorFactory;
public MvcController(IProcessorFactory processorFactory)
{
_processorFactory = processorFactory;
}
public void Method()
{
var processor = _processorFactory.Create();
}
The best solution to your problem is to hide the knowledge of the existence of multiple implementations and the selection between them from the consumer by implementing a proxy implementation for IProcessor:
public sealed ProxyProcessor : IProcessor
{
private readonly ABCProcessor abc;
private readonly PQRProcessor pqr;
private readonly IProcessorConfig config;
public ProxyProcessor(ABCProcessor abc, PQRProcessor pqr, IProcessorConfig config) {
this.abc = abc;
this.pqr = pqr;
this.config = config;
}
// Implement IProcessor methods to forward to the CurrentProcessor.
public void Process() => CurrentProcessor.Process();
private IProcessor CurrentProcessor => config.ProcessorType == "ABC" ? abc : pqr;
}
By doing this you can delegate to the correct implementation at runtime while the consumer stays oblivious to the fact that you make a decision at runtime about this. Now instead of injecting either an ABCProcessor or PQRProcessor into the consumers, you now inject a ProxyProcessor into the consumers. For instance, this is how the object graph for the ProxyProcessor could look like:
IProcessor processor =
new ProxyProcessor(
abc: new ABCProcessor(),
pqr: new PQRProcessor(),
config: new SqlProcessorConfig("constr"));
Note that this solution has several benefits over the use of a factory, such as:
It prevents having to make any changes to the consumers; the consumers stay oblivious.
It prevents introducing unneeded complexity into the consumers; with the factory approach, consumers have to deal with with an extra dependency. This complicates code and tests.
It causes object graphs to be constructed in a delayed fashion, which complicates verification of object graphs.
Please read this article if you want to know more about why factories hardly ever are the right abstraction.