Caching using #Cacheable with Spring MongoDB integration in spring boot and redis - redis

I was wondering if it's possible to use #Cacheable annotations on the spring data mongo repositories. For example like this:
public interface UserRepository extends MongoRepository<User, String> {
#Cacheable("byId")
public interface UserRepository extends MongoRepository<User, String> {
User findById(String id);
}
}
I'd like to do it on the interface class itself and avoid having a wrapper class if possible. In addition, is there a sample for how to do the cache config for redis with java config (not xml)?

Yes, you can use Cacheable on any public method with spring aspects. You also have to use EnableCaching in any configuration class and optionally a CacheManager bean.

Related

CDI injection not working in REST Resource in WAS Liberty with Jersey as JAX-RS implementation

I am using websphere liberty 19.0.0.8 and I wanted to use Jersey instead of default CXF for jax-rs implementation. I removed jaxrs-2.1 feature from server xml and packaged jersey implementation jars in my webapp .war.
<featureManager>
<feature>servlet-4.0</feature>
<feature>jndi-1.0</feature>
<feature>requestTiming-1.0</feature>
<feature>monitor-1.0</feature>
<feature>localConnector-1.0</feature>
<feature>restConnector-2.0</feature>
<!-- Do not add enabled webProfile-8.0 because we want to disable default
REST implementation (Apache-CXF) provided by Liberty. We want to use Jersey
as our REST implementation because it better support multi-part streaming, -->
<!-- <feature>webProfile-8.0</feature> -->
<feature>jsp-2.3</feature>
<feature>cdi-2.0</feature>
<feature>managedBeans-1.0</feature>
<feature>jdbc-4.2</feature>
<!-- <feature>jaxrs-2.1</feature> -->
</featureManager>
Gradle build including jersey implementation
//JxRS Jersey implementation
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.25.1'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.25.1'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.25.1'
compile group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-json-provider', version: '2.9.0'
Extended jersey's ResourceConfig to configure my RestApplication
#ApplicationPath("/")
public class RestApplicationConfig extends ResourceConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(RestApplicationConfig.class);
public RestApplicationConfig() {
super();
configureResourcesAndFeatures();
}
private void configureResourcesAndFeatures() {
packages(RestApplicationConfig.class.getPackage().getName());
register(MultiPartFeature.class);
}
}
With all this setup my rest api works and I am able to make use of Jersey's multiple related classes in my code.
Now the problem is with CDI. In my resource class I am able to inject CDI managed resource/classes for example
#ApplicationScoped
#Path("/ping")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class PingResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PingResource.class);
#Resource(lookup = "jndi_dpa_iss_rest_url")
private String issRestBaseUrlInResource;
#Inject
private DocumentService documentService;
}
In above class #Resource and #Inject are not able to resolve JNDI resource and managed bean. As soon as I enable jaxrs-2.1 feature in server.xml CDI injection works but then I loose jersey, it uses CXF.
DocumentService and its implementation class is defined as below. Everything is under same package as RestApplicationConfig class or it's sub-packages.
#ApplicationScoped
#Transactional(value = Transactional.TxType.NOT_SUPPORTED)
public class DocumentServiceImpl implements DocumentService {
// some code here
}
What do I need to use CDI in my rest resource classes?
Because there is no jersey extension for CDI 2.0 at the moment, I had to find workaround. Workaround is to manually query CDI container to the the type of bean we are interested in. This way we are manually injecting CDI bean in our resource class but the injected bean is managed bean instance so CDI has taken care of satisfying all its dependecies.
This we we are doing manual injection only in Resource layer but CDI should work fine for layer down.
Working code.
#ApplicationScoped
#Path("/ping")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class PingResource {
private DocumentService documentService = CDI.current().select(DocumentService.class).get();
}
Basically instead of #Inject manually query CDI container.

Spring Data Couchbase Connecting via SSL

Is it possible to configure spring-data-couchbase to connect via SSL?
I have found documentation for how to do this via the SDK, but not in spring-data-couchbase 3.1.4-RELEASE
I think the way to do this is to extend AbstractCouchbaseConfiguration with your own configuration, and then Override the methods in that class with the SSL config as per the SDK documentation. For example:
#Configuration
public class CouchbaseConfig extends AbstractCouchbaseConfiguration {
#Override
public CouchbaseEnvironment couchbaseEnvironment() {
return DefaultCouchbaseEnvironment
.builder()
.sslEnabled(true)
.sslKeystoreFile("/path/tokeystore")
.sslKeystorePassword("password")
.build();
}
}

Spring data rest. How to take repository class through request URI

Can anyone help me please.
I have a few entities and repositories inside my app which is based on spring data rest.
Right now I wrote my own HandlerInterceptor implementation to do preHandling each request and I have to know which repository will use for each http request.
Ofc I can make separate Interceptor for each repository but this solution is not flexible Any ideas?
Thx for advance
Repositories are resolved in spring data-rest using the Repositories class.
The repositories class exposes a helper method (getRepositoryFor(Class<?>)) for finding the repository for a given class.
You can use the following snippet for finding a repository for a given class in your interceptor:
Repositories repositories = new Repositories(appContext);
repositories.getRepositoryFor(entityObject.getClass());
A more elegant solution would be to take advantage of the built-in spring-data-rest repository lookup implementation with a custom controller(RootResourceInformationHandlerMethodArgumentResolver)
For this you just need to add a RootResourceInformation parameter to a RepositoryRestController endpoint method.
#RepositoryRestController
#RequestMapping("/customName")
public class RepositoryExportController {
#Autowired
private ApplicationContext appContext;
#RequestMapping(method = RequestMethod.GET, value = "{repository}",
produces = MediaTypes.HAL_JSON_VALUE)
#ResponseBody
public Resources<Resource<?>> export(RootResourceInformation resourceInformation, ...) {
Repositories repositories = new Repositories(appContext);
CrudRepository repo=(CrudRepository)repositories.getRepositoryFor(resourceInformation.getDomainType());
repo.findAll();
...other logic....
}

Spring Boot ignore ObjectMapper module

In application context I have registered an ObjectMapper module:
#Bean
public SimpleModule jsr310Module() {
final SimpleModule module = new SimpleModule();
module.addSerializer(new LocalDateSerializer());
module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
return module;
}
I tried to debug and it is loaded (or at least the method public void setupModule(SetupContext context) is execute on boot)
but when I call a rest API that return an object with a LocalDate my deserializer is ignored.
Some hint to solve the problem?
To make it work the #Configuration class should extend WebMvcAutoConfiguration
According to the Spring Boot documentation, to configure the ObjectMapper you can either define the bean yourself and annotate it with #Beanand #Primary. There you can register the module. Or you can add a bean of type Jackson2ObjectMapperBuilderwhere you can customize the ObjectMapper.

#inject does not work with stateless EJB

Hi I have a very simple example. I created a resource in javaee 7 as follows:
#Path("greetings")
public class GreetingsResource {
#Inject
Sample s;
#GET
public JsonObject greetings(){
return Json.createObjectBuilder().add("first","1")
.add("second","2")
.add("third","3")
.add("fourth","4")
.add("helloworld", s.helloWorld())
.build();
}
}
Sample is the following simple EJB:
#Stateless
public class Sample {
public String helloWorld(){
return "Hello World";
}
}
Finally the resource Application class:
#ApplicationPath("resources")
public class RestConfiguration extends Application {
}
I can access the URL: "localhost:8081/jasonandjaxrs/resources/greetings"
The problem is that #Inject gives the following error:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=sample,parent=GreetingsResource,qualifiers={}),position=-1,optional=false
But #EJB seems to work. I am trying to understand why #Inject does not work? Thank you.
You can't use CDI (means #Inject) with this setup. CDI only works with beans managed by the container which is not the case for JAX-RS resource classes (your GreetingsResource).
JAX-RS 2.0 does not support injection of EJBs into JAX-RS components
(providers, resources).
If you use #Inject in your case the injection is provided by the HK2 dependency injection framework which isn't aware of normal CDI beans. It even shouldn't work if you use #EJB, I don't know why it works, maybe this has to do with Java EE 7.
As it works for you there should be no problem in using #EJB here, but there are also some alternative approaches in my response to this question.
See also:
Inject a EJB into JAX-RS (RESTfull service)
JERSEY-2040 Add support for injection of EJBs into Jersey-managed providers and resources