#GetMapping and RSocketServer with spring-boot-starter-rsocket - java

Was trying out RSocket Request/Response as specified in section 4 of https://www.baeldung.com/spring-boot-rsocket. So there is a RSocketServer autoconfigured and listening at port 7000. Unable to connect to the method annotated with #GetMapping when hitting the same from browser
#RestController
public class MarketDataRestController {
private final RSocketRequester rSocketRequester;
public MarketDataRestController(RSocketRequester rSocketRequester) {
this.rSocketRequester = rSocketRequester;
}
#GetMapping(value = "/current/{stock}")
public Publisher<MarketData> current(#PathVariable("stock") String stock) {
return rSocketRequester
.route("currentMarketData")
.data(new MarketDataRequest(stock))
.retrieveMono(MarketData.class);
}
}
Expecting to be able to connect to the current() of the class MarketDataRestController annotated with #GetMapping when requesting the same from browser, say e.g.: http://localhost:7000/current/APPLE.
Not sure how to connect to the same.

You can't use #RequestMapping with sockets, use #MessageMapping instead:
instead of #RequestMapping or #GetMapping annotations like in Spring MVC, we will use the #MessageMapping annotation:
#Controller
public class MarketDataRSocketController {
private final MarketDataRepository marketDataRepository;
public MarketDataRSocketController(MarketDataRepository marketDataRepository) {
this.marketDataRepository = marketDataRepository;
}
#MessageMapping("currentMarketData")
public Mono<MarketData> currentMarketData(MarketDataRequest marketDataRequest) {
return marketDataRepository.getOne(marketDataRequest.getStock());
}

Related

how can I do to make it return error when restful url has invalid parameter

#RestController()
#RequestMapping(path = "/users")
public class UserController {
#GetMapping()
public #ResponseBody Page<User> getAllUsers(#RequestParam Integer pageSize, UserRequest userRequest) {
//TODO: some implementation
}}
public class UserRequest{
public String name;
public String age;
}
send the request with invalid parameter, like localhost:8800/users?name1=1234, I want to return error. but in fact it ignore the invalid parameter name1.
I tried to add the user defined annotation on the method parameter and on the class , codes like below
#RestController()
#RequestMapping(path = "/users")
#Validated
public class UserController {
#GetMapping()
public #ResponseBody Page<User> getAllUsers(#RequestParam #Validated Integer pageSize, #Validated UserRequest userRequest} {
//TODO: some implementation
}
}
But it does not working.
I think it is happened because framework has ignore the invalid parameter before the method was called.
where did framework handle the url and how can I do to make it return error instead of ignore?
You can reject parameters that are not valid. You can do so in a HandlerInterceptor class.
Reference: Rejecting GET requests with additional query params
In addition to what is done in the above reference, in your addInterceptors, you can specify the path that is intercepted.
Like this:
#Configuration
public class WebConfig implements WebMvcConfigurer {
private String USERS_PATH = "/users";
// If you want to cover all endpoints in your controller
// private String USERS_PATH = List.of("/users", "/users/**");
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new FooHandlerInterceptor()).addPathPatterns(USERS_PATH);
}
}

#Path works, but #RequestMapping doesn't Java Spring Boot

This works, I am able to make a request in postman for this Service.
#RestController
#Path("sample")
public class SampleClass {
#GET
#Path(value = "/s1")
public Object get() {
//Something
}
}
The problem is when I try to use #RequestMapping instead of #Path, I get a
404 Not Found
Error.
#RestController
#RequestMapping("sample")
public class CommonService {
#GetMapping(value = "/s1", produces = MediaType.APPLICATION_JSON)
public Object get() {
//Something
}
}
What I am doing wrong here?
After a while, I found out that for the JAX-RS (#Path) I had configured in web.xml file a different route "something".
JAX-RS: localhost:8080**/something**/sample/s1
Spring Rest Services: localhost:8080/sample/s1
I was also missing a "/" in the Spring Rest Service.
#RequestMapping("**/**sample")
Full code bellow:
#RestController
#RequestMapping("/sample")
public class CommonService {
#GetMapping(value = "/s1", produces = MediaType.APPLICATION_JSON)
public Object get() {
//Something
}
}

the annotation #CrossOrigin("*") not work

I had the error "Access to XMLHttpRequest at 'http://localhost:8081/products/getPro' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource" while I have added the annotation #CrossOrigin("*") in my spring boot application
#RestController
#RequestMapping("/products")
#CrossOrigin("*")
public class ProductController {
#Autowired
private ProductService productService;
#PostMapping(value = "/getPro", consumes = {"application/json"}, produces =
{"application/json"})
public ResponseEntity<?> getPro(#RequestBody Product product){
return this.productService.getPro(product);
}
In my Frontend I have :
export class ProductService {
public productModel : Product
private baseUrl = 'http://localhost:8081';
constructor(private http:HttpClient) { }
getPro () {
return this.http.post<Product>(this.baseUrl + "/products/getPro",
JSON.stringify(this.productModel));
}
}
Can anyone help me ?
PS :I am using this application like a feign client I mean in reality I am calling another application with FeignClient ! It can be the problem ?
I will suggest you to get rid of #crossOrigin.
You can do following in your config file
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
 
    #Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");// Your allowed paths here
    }
}
I will recommend you to move that all to angular only by using reverse proxy.
{
"/api": {
"target": "http://localhost:8081",
"secure": false
}
}
See github project here. https://github.com/vohra01/parking-demo-SG/blob/master/IdeaProjects/parking-demo/parking-ui-app/proxy.conf.json

Getting 406 Could not find acceptable representation /Spring JSON Test. How to ignore .htm extension in tests?

Controller needs uses .htm extensions for all handlers, including JSON REST endpoints. How should I test for REST endpoints?
Problem:
I cannot disable suffix interpretation and I am getting 406 "Could not find acceptable representation"
Tried attempts:
I reviewed posts on stackoverflow related to 406, but could not find relevant one to the case where 'htm' suffix is used in tests. When you remove '.htm' suffix from both Controller and Test - the test is passing.
Here is controller with /changePassword.htm endpoint:
#Controller
public class MainController {
public static class ResultBean {
private final String result;
public String getResult() {
return result;
}
public ResultBean(String result) {
this.result = result;
}
}
#RequestMapping(value="/changePassword.htm", method= RequestMethod.POST, produces = { "application/json" })
public #ResponseBody ResultBean changePassword (
#RequestParam("username") String username, #RequestParam("password") String password) {
return new ResultBean("OK");
}
}
And here is the test with configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { HomeControllerTest.Config.class })
public class HomeControllerTest {
#InjectMocks
private MainController controller = new MainController();
private MockMvc mvc;
#Configuration
#EnableWebMvc
public static class Config extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreUnknownPathExtensions(true)
.ignoreAcceptHeader(false)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON);
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(controller)
.build();
}
#Test
public void shouldPassChangePasswordBean() throws Exception {
mvc.perform(post("/changePassword.htm")
.accept("*/*")
.param("username", "example")
.param("password", "abcdef")
)
.andExpect(status().isOk()); // Test produces 406 instead of 200
}
}
Any idea?
On newer version of Spring (4+ I think), mime type is determined from suffix first.
So If you use a .htm suffix, Spring will default to produce HTML even if you don't want to.
One way to bypass this is to use a filter that rewrite URL. For instance tuckey URL rewriter filter
With this, you can set some rules like:
/my/page/that/return/json.htm is rewriten to /my/page/that/return/json so that Spring can produce data according to the Accept header.
with Spring 5, try changing your URL of your web service to .json! that is the right fix. great details here http://stick2code.blogspot.com/2014/03/solved-orgspringframeworkwebhttpmediaty.html

Stop Spring MVC annotations processing

I need to stop processing of Spring MVC annotations on interface, but bean for this interface should be created.
e.g. I have shared Api interface with MVC REST annotations, Controller implements this Api. In other project I create REST client based on interface (by processing annotations). But when I create client, Spring sees interface as return type and process annotations inside it. So, I need to stop annotations processing when I create REST client, but for controller annotations should work (now they work OK).
#RequestMapping("/resource1")
public interface Api {
#RequestMapping(method = RequestMethod.POST)
Resource1 getResource1();
}
#RestController
public class Controller implements Api {
#Override
public Resource1 getResource1() {
return null;
}
}
#Configuration
public class Config {
#Bean
public Api api() {
return RestClientFactory.createRestClientBasedOnAnnotations(Api.class);
}
}
I solved it by creating new annotation which is used to mark API interface and overriding boolean isHandler(Class<?> beanType) method of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping. This method originally checks whether class (or any interface that class implements) is annotated with Controller or RequestMapping annotations. I added extra check that looks up for my BackEndApiInterface annotation and if it is found then return false. Here is the code:
#Retention(RetentionPolicy.RUNTIME)
public #interface BackEndApiInterface {
}
#BackEndApiInterface
#RequestMapping("/resource1")
public interface Api {
#RequestMapping(method = RequestMethod.POST)
Resource1 getResource1();
}
#RestController
public class Controller implements Api {
#Override
public Resource1 getResource1() {
return null;
}
}
#Configuration
public class Config {
#Bean
public Api api() {
return RestClientFactory.createRestClientBasedOnAnnotations(Api.class);
}
#Bean
public static RequestMappingHandlerMapping requestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
#Override
protected boolean isHandler(Class<?> beanType) {
if (AnnotationUtils.findAnnotation(beanType, BackEndApiInterface.class) != null) {
return false;
}
return super.isHandler(beanType);
}
};
}
}
you could move the annotations to the implementation and just keep the interface as pure java.

Categories

Resources