Spring Data MongoDB eliminate POJO's - spring

My system is a dynamic telemetry system. We have hundreds of different spiders all sending telemetry back to the SpringBoot server, Everything is dynamic, driven by json files in Mongo, including the UI. We don't build the UI, as opposed to individual teams can configure their own UI for their needs, all by editing json docs.
We have the majority of the UI running and i began the middleware piece. We are using Spring Boot for the first time along with Spring Data Mongo with several MQ listeners for events. The problem is Spring Data. I started reading the docs on it and I realized the docs do not address using it without POJO's. I have this wonderfully dynamic model that changes per user per minute if the telemetry spiders dictate, I couldn't shackle this to a POJO if I tried. Is there a way to use Spring Data with a Map?
It seems from my experiments that the big issue is there is no way to tell the CRUD routines of the repository class what collection to query without a POJO.
Are my suspicions correct in that this won't work and am I better off ditching Spring Data and using the Mongo driver directly?

I don't think you can do it without a pojo when using spring-data. The least you could do is this
public interface NoPojoRepository extends MongoRepository<DummyPojo, String> {
}
and create a dummy pojo with just id and a Map.
#Data
public class DummyPojo {
#Id
private String id;
private Map<String, Object> value;
}
Since this value field is a map, you can store pretty much anything.

Related

Is it possible to set Redis key expiration time when using Spring Integration RedisMessageStore

Dears, I'd like to auto-expire Redis keys when using org.springframework.integration.redis.store.RedisMessageStore class in Spring Integration. I see some methods related to "expiry callback" but I could not find any documentation or examples yet. Any advice will be much appreciated.
#Bean
public MessageStore redisMessageStore(LettuceConnectionFactory redisConnectionFactory) {
RedisMessageStore store = new RedisMessageStore(redisConnectionFactory, "TEST_");
return store;
}
Spring Boot: 2.6.3, spring integration and spring-boot-starter-data-redis.
The RedisMessageStore does not have any expiration features. And technically it must not. The point of this kind of store is too keep data until it is used. Look at it as persistent storage. The RedisMetadataStore is based on the RedisProperties object, so it also cannot use expiration feature for particular entry.
You probably talk about a MessageGroupStoreReaper, which really calls a MessageGroupStore.expireMessageGroups(long timeout), but that's already an artificial, cross-store implementation provided by the framework. The logic relies on the group.getTimestamp() and group.getLastModified(). So, still not that auto-expiration Redis feature.
The MessageGroupStoreReaper is a process needed to be run in your application: nothing Redis-specific.
See more info in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/message-routing.html#reaper

Are template engines (i.e. Thymeleaf) necessary for Spring Boot applications?

I am currently working on a Spring Boot project and I am fairly new to template engines. This will also be my first own private project with Spring Boot.
I would like to know whether it is necessary to include a template engine, such as Thymeleaf, while developing a web application with Spring Boot. I'm using PostegreSQL for the database.
I read under another post that a template engine is not needed, if the backend framework uses JSON for data exchange, because template engines are for rendering retrieved data to HTML for the client. I retrieve JSON objects from the database, can I leave template engines out of my project then?
If any more details are needed, leave a comment below.
No they aren't necessary, in fact most new projects that require web-pages are using single page applications now like Angular, React, Vue, ... over thymeleaf or jsp.
Aside from that a Spring project doesn't always need web pages, for instance when you are just creating a REST API for other applications to call on, or when you are automating things like: a mail service / printing / ... You name it.
However, when you DO want a simple solution with some pages that aren't all that dynamic or complex, pivotal / VMware does recommend to use thymeleaf (over jsp and other solutions) because it integrates easily.
I read under another post that a template engine is not needed, if the backend framework uses JSON for data exchange, because template engines are for rendering retrieved data to HTML for the client. I retrieve JSON objects from the database, can I leave template engines out of my project then?
This is partly true. Yes, Thymeleaf and alike are mostly intended to render data to HTML. They can render any text data, including JSON, but there are tools better suited for the job. On other hand it does not matter how you store the data in your database or what database you are using. You can't just skip rendering (serializing) the response so it does not matter how you store it. What matters is what you want to return as response. For HTML Thymeleaf or even JSP are suitable, but for JSON you may want to use Jackson or Gson instead.
You didn't mentioned the technology you are going to use, so for my examples I'll assume you intend to use Spring Web MVC. Lets take a look at "traditional" controller:
#Controller
public class GreetingController {
#GetMapping("/greeting")
public ModelAndView greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new ModelAndView("greeting", "greeting", new Greeting(name));
}
}
When you make GET request to "/greeting", Spring will call greeting and get the object it returns. In this case it contains the model (the data we want to render) and the view (the template file to use). Then it will try to find a view (something like greeting.html or greeting.jsp) and use template engine like Thymeleaf (or whatever else is configured) to render it (typically to HTML).
What if we want to return JSON instead? In this case we need to:
modify greeting to return Greeting instance instead of ModelAndView
Use RestController instead of Controller. This will tell Spring MVC that we want to directly serialize the object returned to JSON (or similar format) instead of using template to do that.
Here is the modified example:
#RestController
public class GreetingController {
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(name);
}
}
Spring MVC still needs some help to serialize the Greeting instance to JSON. But if you use Spring Boot and the web starter, you don't have to worry about it. It will include Jackson for you.
This is in no way exhaustive answer. As a matter of fact it skips a lot of details, but I hope nevertheless it is useful one. If you want to create REST API using JSON, this Building a RESTful Web Service guide is a good place to start. If you follow the Starting with Spring Initializr steps you'll get a project setup with only what is needed (well maybe with a bit extra but I would not worry too much about it).

Couchbase modify meta data experation using Spring

When using Spring Couchbase connector I can easily get version for optimistic locking by having this in my class:
public class MyClass {
#Version
private String version;
.... rest of class omitted ....
}
I'm now trying to find a similar way to get and be able to modify the meta data for expiration. I'm unable to find how to do this.
Can someone please give an example? Thanks!
With spring data couchbase library (until the latest Version 3.0.8.RELEASE), document expiry can be defined by using #Document(expiry = 10) or #Document(expiryExpression = "${valid.document.expiry}") on the class. There is also an optional boolean attribute touchOnRead which needs to be added with #Document, which would reset the expiry timer whenever the document is directly read. Please note that currently the expiry of an existing document cannot be read/modified directly with this library. One way would be to access the below APIs exposed by Couchbase's own java SDK (com.couchbase.client.java)
getAndTouch - allows you to retrieve a document while modifying its expiration time
touch - allows you to modify a document’s expiration time without otherwise accessing the document
You can find the method signatures of the above two here : http://docs.couchbase.com/sdk-api/couchbase-java-client-2.2.4/com/couchbase/client/java/Bucket.html
The above two APIs can be accessed via the spring data couchbase library as follows
couchbaseTemplate.getCouchbaseBucket().touch(...)
couchbaseTemplate.getCouchbaseBucket().getAndTouch(...)
The getCouchbaseBucket() method of the spring library returns a reference to com.couchbase.client.java.Bucket using which the touch and getAndTouch methods can be used.

Dynamically configuring spring state machine

Some queries on spring state machine.
Can we have more than one state machine in a single spring project,
where in one state machine serves for one work flow (may be a CD
player work flow) and the other for a turnstile?
Can I dynamically load the configuration in my config class, for instance from a big data source having JSON formatted data, where we stores our states, events, transitions etc.
One of my requirement is I may be having a frequently changing worklow or model, which I needs to configured in my spring project. How can I effectively do that with spring state machine.
1) You can have multiple machines. #EnableStateMachine has id property for a bean name. You can expose config as #EnableStateMachineFactory. If you want to work outside of javaconfig there is a manual builder model for it.
2/3) There is a public configuration api between javaconfig and statemachine. One user(outside of javaconfig) of this config model is uml based modeling which uses eclipse's uml xml file to load the config. Uml is your best bet as we don't have other build-in configuration hooks at this moment. contributions welcome ;)
You can configure the State machine dynamically using Builder. Builder is using same configuration interfaces behind the scenes that the #Configuration model using adapter classes.
Example:
StateMachine<String, String> buildMachine1() throws Exception {
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial("S1")
.end("SF")
.states(new HashSet<String>(Arrays.asList("S1","S2","S3","S4")));
return builder.build();
}
Link to official docs: Dynamic Spring State Machine

How to expose the resourceId with Spring Data Rest

I had was to expose the primary key which is annotated with #Id in entity.the ID field is only visible on the resource path, but not on the JSON body.
You can configure this using the RepositoryRestConfigurerAdapter on entity level.
#Configuration
public class ExposeEntityIdRestConfiguration extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(MyEntity.class);
}
}
Be aware that using this you are working against the principles of spring-data-rest - sdr promotes hypermedia to be able to use an API by navigating between resources using links - here your resources are identified and referenced by links and thus the ids are not needed anymore. Using ids on your client pushes the complexity of constructing links to resources to the client. And the client should not be bothered with this knowledge.
The best solution would be not to using the IDs of your entities, and use the link references the hypermedia provides.
You just need to parse your JSON accordingly to the HAL specification used by Spring Data Rest.

Resources