Using RepositoryRestResource annotation to change RESTful endpoint not working - java

I am new to Spring boot. I was trying to create RESTful web service which also plugs into MongoDB.
Everything works fine as the guide explains except for this.
package hello.requests;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import hello.models.CustomerModel;
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface CustomerRepository extends MongoRepository<CustomerModel, String> {
List<CustomerModel> findByLastName(#Param("name") String name);
}
Here I am trying to change the RESTful endpoint for the repository from the default /customerModels to /people. But when I run this, I get 404 if I try /people but works fine for /customerModels.
In a broader sense how does #RepositoryRestResource work?
What am I doing wrong here?

You can't use slash inside the path attribute, but you can set base path in application.properties:
# DATA REST (RepositoryRestProperties)
spring.data.rest.base-path=/my/base/uri
# Base path to be used by Spring Data REST to expose repository resources.

Without seeing your entire configuration it is hard to know exactly what is going on in your situation. However using the latest guide at https://github.com/spring-guides/gs-accessing-data-mongodb.git I am able to get it working by making the following changes:
Adding spring-boot-starter-data-rest as a dependency in the POM file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
Adding this annotation to the CustomerRepository class.
#RepositoryRestResource(path = "people")
Setting up getters and setters in the Customer class for the 2 name fields in the constructor to avoid a Jackson serialization error.
Using this when I run the application I am able to access the repository at http://localhost:8080/people. If I remove the annotation then the CustomerRepository is accessed at http://localhost:8080/customers. Let me know if you want me to post a fork on GitHub.
To answer your question about what RepositoryRestResource is that it overrides the attributes for the ResourceMapping that is created by default. It's attributes are used in creating the mapping and change the related return values of the methods on the mapping class. By default Spring Data Rest creates defaults based on the class names of the objects used in the repository definition.

/customerModels is generated by default because your default method returns a list of CustomerModel. So you may try to add this #RestResource(path = "names") to your method and then access it like:
http://localhost:8080/yourapp/people/search/names. Look here: Spring data docs

Related

Spring generates two beans of the same instance "MyRepository"

i'm fairly 'new' to Spring Boot and need a bit of help with CrudRepositories.
My problem is the following: When I want to start my Spring Boot Application, it starts just fine, creates all the tables in the database, but somehow manages to fail, because Spring creates two beans of the same interface:
Note that my package hierarchy looks a bit different. Spring Boot however is referencing the exact same interface, twice.
The bean 'IMyRepository', defined in com.package.IMyRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration, could not be registered. A bean with that name has already been defined in com.package.IMyRepository defined in #EnableJdbcRepositories declared on JdbcRepositoriesRegistrar.EnableJdbcRepositoriesConfiguration and overriding is disabled.
For clarification: I do not have two interfaces declared wit the same name, I do not have any MyRepositoryImpl classes, and I do not have multiple projects with the same hierarchy. (only one: src/main/.../com.(...).IMyRepository)
My Repository interface looks like this:
package com.package.api.components.account.repository;
import com.package.api.components.account.entity.Account;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface IMyRepository extends CrudRepository<Account, Long> {
Account findByEmail(String email);
Account findByEmailAndPassword(String email, String password);
}
And the only single time where, I am taking usage of IMyRepository is in this class:
#Component
#AllArgsConstructor
public class AccountService implements IAccountService, IRegisterService, ILoginService {
private final IAccountRepository accountRepository;
private final IPasswordValidationService passwordValidationService;
private final AAccountMapper accountMapper;
// Code
}
Here are some answers on StackOverflow & co I've already tried, which none off them worked for me:
https://coderanch.com/t/747155/java/bean-defined-myRepository
Spring Boot detects 2 identical repository beans
Thanks you very much for reading this!
Don't put #Repository (or #Component) on the interface, only on the implementation.
As stated in the comments of #M. Deinum, the problem was, that (in my case) I had two spring-boot-starter-data-... dependencies, both of which wanted to create beans of the same class/interface, with the same Impl name.
I solved the problem, by following their instructions:
I deleted the dependency spring-boot-starter-data-jdbc
I also deleted the library from the project and classpath
Another problem was, that my project wouldn't keep running. I, again, solved this problem by following their instructions:
I added the spring-boot-starter-web dependency

Spring Boot - cache not working, how to set cache up correctly?

My application is on Spring boot 1.5.1
I have looked up all common problems related to caching not working in spring boot (calling a cacheable method from the same class, etc) and I still can't seem to pinpoint why my method is not cacheing. I am just trying to use the simple cache built into Spring (ie the concurrent hashmap).
Setup: in pom.xml I added this
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
My configuration class is the following:
#SpringBootApplication
#Configuration
#EnableCaching
#EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have a controller class that has the following method to get a list of versions.
#RequestMapping(value = "/getVersionList", method = RequestMethod.GET)
public JSONObject getVersionList() {
JSONObject retJSON = new JSONObject();
List<String> versions = fetchVersionService.getVersionList();
retJSON.put("versions", versions);
return retJSON;
}
And the FetchVersionService class where I have the cacheable method to cache this versions list
#Cacheable("versions")
public List<String> getVersionList() {
System.out.println("If there is something in the cache, it should not hit here.");
return randomService.getVersions(); //another service class that gets versions from a remote location, which takes a long time
}
Whenever I make multiple GET calls to this function, it always goes inside the function even though I only expect to it execute the function once. For some reason it isn't cacheing the results.
Any ideas where I went wrong with my setup? Thanks a lot.
In the comments under this question #irfanhasan mentions that they had imported the wrong package but there was no certain response.
I faced the same problem. I tried to use #Cachable annotation but it wasn't work. I found that it was imported as:
import springfox.documentation.annotations.Cacheable
Instead of:
import org.springframework.cache.annotation.Cacheable;
Look carefully for your IDE imports.
In the comments under this question, #irfanhasan mentions that they had imported the wrong package and #xetra11 replied asking which package was wrong which there was no reply to. I am not #irfanhasan but it might have been the following mixup: "You can also use the standard JSR-107 (JCache) annotations (such as #CacheResult) transparently. However, we strongly advise you to not mix and match the Spring Cache and JCache annotations."

requestmapping invalid after configuring entity path

I have a project called models which i import via maven, it consists of Hibernate Entities,
I setup this models project as a dependency on a project that i have configured Spring, it uses spring boot.
if i try to run the project it tells me that Not a managed type:when i reference an entity from the models project. i managed to fix it using the following annotations
#EnableJpaRepositories({"com.rajeeda.coopmis.models.*", "com.rajeeda.coopmis.web.*"})
#ComponentScan(basePackages = { "com.rajeeda.coopmis.web.*" , "com.rajeeda.coopmis.models.*"})
#EntityScan({"com.rajeeda.coopmis.models.*", "com.rajeeda.coopmis.web.*"})
```
once i setup the path to models then spring boots up fine, but none of the #RequestMapings from spring is being reached. as i get a 404 screen, i tried seven specifying path using
server.servlet.contextPath=/mainstay`
still no luck, is there a way i can explicitly provide the path of controllers?
if i remove the above annotations from the Application class then the end points works but i get the not managed entity error (i test and confirm the controllers are working when i remove the following class
public interface UserRepository extends CrudRepository<ItUserMaster, Integer> {}
if anyone has faced the same problem please do share. thanks in advance
Not sure this will solve the issue, but you can give it a try.
Let us use basePackages and remove the wildcard like this:
#EnableJpaRepositories(basePackages = {"com.rajeeda.coopmis.models", "com.rajeeda.coopmis.web"})
#ComponentScan(basePackages = { "com.rajeeda.coopmis.web" , "com.rajeeda.coopmis.models"})
#EntityScan(basePackages = {"com.rajeeda.coopmis.models", "com.rajeeda.coopmis.web"})

Elasticsearch spring implementation error

I have a interface which has function used to query ElasticSearch. It extends the ElasticsearchRepository for doing it.
public interface HouseholdRepository extends ElasticsearchRepository<SearchHouseholdESBean, String> {
List<SearchHouseholdESBean> findByPhoneNumberAndActiveInd(String phoneNumber, String activeInd);
The problem is how do i call this in my business class where i need to get the results. This being an interface , i can't create an object of this to call the methods. Also, the implementation is implicit to the jars in the Elastic Search.
To use elastichsearch repositories you must follow the next steps:
1. add annotation #EnableElasticsearchRepositories on your SpringBootApplication
#SpringBootApplication
#EnableElasticsearchRepositories
public class Application {
//...
2. Make sure that the interface HouseholdRepository is scanned by the spring-boot application. You can simple achieve this by placing it under the same root package as your Application class.
3.You will just #Autowire HouseholdRepository in your service without further changes. The idea behind spring boot data is that the code will be generated based on that interface.
OBS: make sure that you have the proper project dependencies. You should depend on spring-boot-starter-data-elasticsearch to avoid extra configuration effort.

Swagger Spring API

I am using Spring Swagger library v1.0.2
Maven:
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.2</version>
</dependency>
I am able to scan my REST APIs and view it on the Swagger UI. I have even implemented OAuth and it is working great.
However, there is one feature that I need to implement. I want to hide some of the REST APIs. I need to do this at the class level as well as on the method level. I read about an 'hidden' attribute in the #Api annotation. I set it to 'true' but I can still see my class and all its method being displayed in the Swagger UI.
Example:
#Api(
description="This class is not covered by Spring security.",
value="/unauthorize",
hidden=true)
#RequestMapping("/unauthorize")
#Controller
public class UnauthorizeResource {}
Can someone please tell me how I can prevent the 'UnauthorizeResource' class from being displayed?
You can utilize the #ApiIgnore annotation:
#ApiIgnore
#RequestMapping("/unauthorize")
#Controller
public class UnauthorizeResource {}

Categories