Spring Data Rest integration with Spring HATEOAS - spring

From various documents and tuts, I've earned and learned following points so far:
Spring Data Rest (SDR) used for exposing our Spring Data Repository as REST service, so that one can use it for self exploring, without any need of creating JAXRS manually. It only works for Repository layer, and we cannot control its way of working in terms of modification or addition other than the configuration using RepositoryRestMvcConfiguration. It uses Spring HATEOAS internally somewhere.
Spring HATEOAS is made for creating links within Entities we return through Controller or REST endpoints. We got ResourceSupport to extend our entity or Resource wrapper class to wrap our Entity to create or add links. There are several Annotations and classes to use such as #EnableHyperediaSupport and EntityLinks.
There may be some points which I am yet to explore or get to know about, but I was just curious about How can we combine SDR into HATEOAS link building process ? Say for eg.
EntityBean bean = repository.findByName(name);
Resource<EntityBean> resource = new Resource<EntityBean>(bean);
//JaxRsLinkBuilder.linkTo(TestResource.class).withRel("entity") // this also works
//ControllerLinkBuilder.linkTo(TestResource.class).withRel("myRel") // this also works
// I am curious how ControllerLinkBuilder and JaxRSLinkBuilder both are working for JaxRS.
//Here TestResource is my REST service class. now in below line:
resource.add(JaxRsLinkBuilder.linkTo(MyRepository.class).withRel("sdf")); //not working
// MyRepository is SDR exposed repository, which I thought should work but not working.
return resource;
So, I just wanted to include my exposed REST repository into manual HATEOAS link building process.. is it possible to do so ?

You should able to use Spring-HATEOAS ResourceProcessor to build links.
Example:
#Component
public class MyBeanResourceProcessor implements ResourceProcessor<Resource<MyBean>> {
#Autowired
private EntityLinks entityLinks;
public Resource<MyBean> process(Resource<MyBean> resource) {
MyBean mybean = resource.getContent();
// Do your linking here using entity class
//EntityBean bean = repository.findByName(name);
//Resource<EntityBean> resource = new Resource<EntityBean>(bean);
// assuming you are linking to a single resource and bean.getId() method... check entitylinks for other methods
//resource.add(entityLinks.linkForSingleResource(bean.class,bean.getId()).withRel("sdf"));
return resource;
}
}

Related

Spring dependency injection in a non-spring boot application

I writing a library which doesn't have a main and isn't a Spring Boot application but I'd still like to use Spring Framework's dependency injection to load the dependencies of my classes. I'd like this library to be available to everyone, even developers who aren't going to be using Spring.
Is there a way for me to take advantage of Spring Framework's dependency injection even if the users of my library won't be using Spring?
Currently I'm importing my library into another one of my apps but my dependencies are turning out as null. Is there a way to get around this?
#Component
public class Client
{
#Autowired
private ClientService clientService; // this is null
public static Client createClientWithCredentials(String clientId, String clientSecret)
{
return new Client(clientId, clientSecret);
}
private Client(String clientId, String clientSecret)
{
// ...
}
}
#Service
public class ClientService {
// ...
}
Someone using my library would use instantiate it like this.
...
// Non-Spring project
Client client = Client.createClientWithCredentials("id", "secret");
...
Unfortunately using client will at some point throw a NullPointerException since clientService is null. I'm also testing my app this way and this is why I know that I have null dependencies.
How can I take advantage of Spring's Dependency Injection if my app is never run but only used as a library?
Is this possible or do I need to use the old way of every class constructing it's own dependencies?

How can I force #AutoConfigureJsonTesters to use HAL format from spring-hateoas?

I have a small module that should only contain the resource model of my REST service. I want to create a test in this module to ensure that the resource model serializes and deserializes appropriate HAL format.
I have a single test and this is the configuration:
#RunWith(SpringRunner::class
#SpringBootTest
#AutoConfigureJsonTesters
class MyTest {
#Autowired
private lateinit var collectionTester: JacksonTester<Resources<Entity>>
....
}
and a very simple configuration
#SpringBootConfiguration
class TestConfig
When calling collectionTester.write on a list of Entity (which extends ResourceSupport) I don't get an _embedded field, instead I get
{"links":[],"content":[...]}
which is not HAL format.
How can I force #AutoConfigureJsonTesters to give me a JacksonTester with an ObjectMapper configured for HAL?
Spring Boot 2.0.0.RELEASE
Thanks!
The auto-configured JacksonTester will use the context’s ObjectMapper which won’t have any of the Spring HATEOAS stuff configured on it. You might be better creating a JacksonTester yourself and passing it an appropriately configured ObjectMapper to use.
I believe Spring HATEOAS has a module that it applies to the ObjectMapper to configure it. If you get stuck with that, asking in gitter/spring-projects/spring-data is probably your best bet as Spring HATEOAS is maintained by the Data team due to it being used by Spring Data REST.

Decorate spring boot repository

I'm working on a Spring Boot API that's supposed to be deployed later this month. We created our own interface for a repository, and extended the CrudRepository. Spring boot autowires everything.
What I would like to do is add more logging capabilities, such as LOGGER.info("searched for solution ID").
Currently our code looks like this:
#Repository
public interface ProductSolutionRepository extends CrudRepository<ProductSolution, String> {
public List<ProductSolution> findBySolutionId(#Param("solutionId") int solutionId);
Since Spring configures everything don't really see a way of decorating these functions to add logging functionality. Can someone help me out by pointing me to the documentation, showing a nice example, or explaining the concept behind logging decorators?
First, I would like to point out some redundant codes for you.
You don't need to annotate the repository with #Repository, spring boot can autowire it automatically.
#Param is used when you write a sql with #Query, you just need to declare your parameters here.
The repository is the dao layer. A normal practice, you should create a service for each repository and autowire the repository into the service. Then you can implement transaction or write logs there.
You can use a single file AOP Logging Aspect using AspectJ cutting across your repository interfaces layer and logging method name, input args and output.
Assuming for this purpose a RepositoryLoggingAspect class, you'd have to annotate it first with #Aspect:
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class RepositoryLoggingAspect {
//..
}
And then create a Pointcut aiming at your repository package you want to cut-accross:
#Pointcut("within(package.of.my.repositories..*)")
public void repositoriesPackagePointcut() {}
And finally define the logging logic in an #Around annotated method:
#Around("repositoriesPackagePointcut()")
public Object logMyRepos(ProceedingJoinPoint joinPoint) throws Throwable {
//log method name using: joinPoint.getSignature().getName()
//log method arguments using: Arrays.toString(joinPoint.getArgs())
//store and log method output using: Object myResult = joinPoint.proceed();
}

Spring data - Manual implementation

Is it possible to write my own function implementation along usage of spring repositories?
I would like to actually implement the function
getUserByFirstName()
and not get it automagically.
While i still want to get
getUserById()
automagically from spring-data.
1) is it possible?
2) is it possible to achieve logging for all methods spring data automagically generates? (or should i write them manually with
logger.log("entering method ...");
See section 1.3 of the manual for the first requirement:
http://docs.spring.io/spring-data/jpa/docs/1.4.2.RELEASE/reference/html/repositories.html#repositories.single-repository-behaviour
For the second requirement I guess some AOP based solution might work for you well here. See here for example using Spring's AOP support:
logging with AOP in spring?
Yes, you can!!!
There is an amazing feature in Spring data that allows this:
Create an interface with your custom method:
public interface UserRepositoryCustom {
User getUserByFirstName();
}
Make your Spring Data interface extends this new interface, as well as the Spring data crud interface (or JPA, Mongo or whatever spring data interface you're extending):
public interface MySpringDataRepository extends CrudRepository<User, Long>, UserRepositoryCustom {
}
Create a class that implements only your custom interface. The name of the class must be Impl, for instance: UserRepositoryImpl:
public class MySpringDataRepositoryImpl implements UserRepositoryCustom {
public User getUserByFirstName(){
//Your custom implementation
}
}
Now, you only need to inject the Spring data repository in your service and you can use both methods: the spring-data implemented method and your custom implemented method:
#Inject private MySpringDataRepository myRepository;
That's it!!
Look at this section in the documentation:
Spring Data Custom implementations

JAX-RS Jersey/Grizzly Define an interface resource

Following the example here On deploying a sample resource using the Grizzly container.
It uses a resource that is defined as a class, instead I would like to define an interface with the annotations and have the resource class implements that interface.
The problem now is that Grizzly complains that it can't find the resource:
com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.
On Main class, where "com.mycompany.pack" is the package containing the implementation class:
final String baseUri = "http://localhost:9999/";
final Map<String, String> initParams = new HashMap<String, String>();
initParams.put("com.sun.jersey.config.property.packages", "com.mycompany.pack");
[Edit]: It works however when adding the annotations on the class as well.
If there is a way to have the annotations declared only at the interface level.
You can't do it with package scanning because that only looks for classes with the JAX-RS annotations on them. You'll have to use a different approach: either one of the configuration options mentioned in the Jersey user guide that lets you explicitly declare your resource classes, or you could also use jersey-spring to manage your instances. With jersey-spring, there are no extra steps to be able to use an interface like you want to. You just annotate the interface, make the implementation a Spring bean, and it works.

Resources