I was using SwaggerHub recently and tried to upgrade the spring-boot version (1.5.22.RELEASE to 2.3.3.RELEASE) in the generated Spring-Boot api, because of the access management (Keycloak).
Upgrading spring-boot version to 2.0.1.RELEASE does fix the issues using Keycloak, results in 404 error for every path of the api though. Summarily, no path can be accessed, despite being mapped according to the log.
Issues with the Versions:
1.5.22.RELEASE: API-Path can be accessed - Getting NoClassDefFoundError: WebServerFactoryCustomizer
2.0.0.RELEASE - 2.0.9.RELEASE: API-Paths are being mapped, but no access - No Error with Keycloak at startup.
2.1.0.RELEASE - 2.3.3.RELEASE: API-Paths don't get mapped - No Error with Keycloak at startup.
This is a section of the log using 2.0.1.RELEASE:
2020-10-05 10:46:47.012 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getIcnByNumber],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.ModelConfiguration>> io.swagger.api.GetIcnByNumberApiController.getIcnByNumber()
2020-10-05 10:46:47.015 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getMyConfigurations],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.ModelConfiguration>> io.swagger.api.GetMyConfigurationsApiController.callConfiguration()
2020-10-05 10:46:47.017 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getMyProjects],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.ProjectModel>> io.swagger.api.GetMyProjectsApiController.getMyProjectsGet()
2020-10-05 10:46:47.020 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getProjectConfiguration/{projectId}],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<io.swagger.model.ProjectConfiguration> io.swagger.api.GetProjectConfigurationApiController.getProjectConfigurationProjectIdGet(java.lang.String)
2020-10-05 10:46:47.021 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getRequestOverview],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.RequestOverview>> io.swagger.api.GetRequestOverviewApiController.getRequestOverview()
Code-Example:
/getMyConfigurations - Interface:
/**
* NOTE: This class is auto generated by the swagger code generator program (3.0.21).
* https://github.com/swagger-api/swagger-codegen
* Do not edit the class manually.
*/
package io.swagger.api;
import io.swagger.model.ModelConfiguration;
import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.bind.annotation.CookieValue;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-09-14T09:55:45.552Z[GMT]")
#Api(value = "getMyConfigurations", description = "the getMyConfigurations API")
public interface GetMyConfigurationsApi {
#ApiOperation(value = "searches inventory", nickname = "callConfiguration", notes = "By passing in the appropriate options, you can search for available inventory in the system ", response = ModelConfiguration.class, responseContainer = "List", tags={ "developers", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "search results matching criteria", response = ModelConfiguration.class, responseContainer = "List"),
#ApiResponse(code = 400, message = "bad input parameter") })
#RequestMapping(value = "/getMyConfigurations",
produces = { "application/json" },
method = RequestMethod.GET)
ResponseEntity<List<ModelConfiguration>> callConfiguration();
}
/getMyConfigurations - Controller:
package io.swagger.api;
import io.swagger.model.ModelConfiguration;
import io.swagger.model.Originator;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.*;
import javax.validation.Valid;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-08-28T09:14:46.542Z[GMT]")
#Controller
public class GetMyConfigurationsApiController implements GetMyConfigurationsApi {
private static final Logger log = LoggerFactory.getLogger(GetMyConfigurationsApiController.class);
private final ObjectMapper objectMapper;
private final HttpServletRequest request;
#org.springframework.beans.factory.annotation.Autowired
public GetMyConfigurationsApiController(ObjectMapper objectMapper, HttpServletRequest request) {
this.objectMapper = objectMapper;
this.request = request;
}
public ResponseEntity<List<ModelConfiguration>> callConfiguration() {
ArrayList<ModelConfiguration> mcList = new ArrayList<>();
return new ResponseEntity<List<ModelConfiguration>>(mcList,HttpStatus.OK);
}
}
EDIT (05.10.2020): Styling for better overview.
Tried to access the path on localhost:8080/TEST/API/1.0.0/getMyConfigurations which was functioning with version 1.5.33.RELEASE.
Seems like the server.contextPath attribute on application.properties is ignored in versions higher than 2.x.x.RELEASE. So it turned out that the path has to be called without server.contextPath (localhost:8080/getMyConfigurations).
Edit:
The property was moved from server.contextPath (or server.context-path) to server.servlet.context-path as described here
#martinspielmann thank you for the comment.
Related
I am learning Spring AOP and tried to call the #BeforeAdvise for two Different methods in different classes. But the log added in the first call is getting printed only. Please check the code below and let me know what is not correct here.
MainClass
package com.example.aspects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.aspects.AopClasses.DemoConfig;
#SpringBootApplication
public class AspectsApplication {
public static void main(String[] args) {
SpringApplication.run(AspectsApplication.class, args);
}
}
AspectClass
package com.example.aspects.Acpects;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class MyLoggingDemo {
private static final Logger logger = LogManager.getLogger(MyLoggingDemo.class);
#Before("execution(public String test())")
public void beforeCheck() {
logger.info("Before Check !!!!!!!!!!!! "+System.currentTimeMillis() );
}
}
ConfigClass
package com.example.aspects.AopClasses;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan("com.example.aspects")
public class DemoConfig {
}
TestClass- Where the first call is made to the function
package com.example.aspects.AopClasses;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/")
public class tesTClass {
private static final Logger logger = LogManager.getLogger(tesTClass.class);
MemberShipDAO dao = new MemberShipDAO();
#RequestMapping(value = "/")
public String test() {
logger.info("Hey I am here");
return "HEy There I am Working !!";
}
#RequestMapping(value ="/test")
public String testing() {
logger.info("MemberShipDAO Call");
return dao.test(); // method with same name called here again
}
}
MemberShipDAO - Declared the test method again here
package com.example.aspects.AopClasses;
import org.springframework.stereotype.Component;
#Component
public class MemberShipDAO {
public String test() {
return "HEy!!";
}
}
Console
2022-01-18 11:37:52.794 INFO 8032 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-01-18 11:37:52.796 INFO 8032 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-01-18 11:37:52.802 INFO 8032 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
2022-01-18 11:37:52.811 INFO 8032 --- [nio-8080-exec-1] c.example.aspects.Acpects.MyLoggingDemo : Before Check !!!!!!!!!!!! 1642486072811
2022-01-18 11:37:52.854 INFO 8032 --- [nio-8080-exec-1] c.example.aspects.AopClasses.tesTClass : Hey I am here
2022-01-18 11:37:57.383 INFO 8032 --- [nio-8080-exec-3] c.example.aspects.AopClasses.tesTClass : MemberShipDAO Call
Change this
MemberShipDAO dao = new MemberShipDAO();
to this
#Autowired MemberShipDAO dao;
Spring's magic for the AOP happens only when you use the instance created by Spring. Behind the scene, Spring instantiated your dao and wrapped it with a proxy that makes a call to your aspect.
Currently I have created 2 microservices and and getting the data from one service to another using RestTemplate.
Microservice -1:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
#RestController
public class StringDataController {
List<String> stringList = new ArrayList<>();
#RequestMapping(value = "/securities/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<String> sendStringData(){
stringList.add("12345");
stringList.add("23435");
stringList.add("23436");
return stringList;
}
}
Microservice-2:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
#RestController
#EnableAutoConfiguration
public class ExternalRequestController {
#Value ("${sampleMS1.uri}")
String sampleMS1URI;
#RequestMapping(value="/listdata", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public void receiveStringFromAnotherMS(){
List<String> list = null;
list = new RestTemplate().getForObject(sampleMS1URI,List.class);
System.out.println(list.toString());
System.out.println("-->"+list);
}
}
Now, I have to send the List(String)(list of ID's) data to some external server and response should get Map(K,V) ==> key as a String and Value as a Double.
Note: The external server is not handling by us, so we can only request the data with List of id's and then they should sending the response with price data of specific id's.
Can anyone suggest me a way to do it ?
I am new to Spring & Spring boot.
Thank you!
I am trying to generate a TEXT/PLAIN response for my Spring application.
When I am debugging the code, I see the string nicely formatted:
LINE1
LINE2
...
But when I see the response in Postman I see that the output is all messed up like
LINE1\nLIINE2\n....
I am not sure if the set up the controller properly or not!
Here is my Controller class:
import java.io.StringReader;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#Configuration
#EnableAutoConfiguration
public class ConfigGeneratorController {
private final AtomicLong counter = new AtomicLong();
Logger logger = null;
#RequestMapping(value = "/configGenerator", method = {RequestMethod.POST})
#Consumes({MediaType.APPLICATION_XML_VALUE,MediaType.APPLICATION_JSON_VALUE})
#Produces({MediaType.TEXT_PLAIN_VALUE})
public ConfigGenerator configGenerator(#RequestBody String xml) {
logger = Logger.getLogger(ConfigGeneratorController.class.getName());
.
.
.
bunch of code
.
.
.
return new ConfigGenerator(counter.incrementAndGet(), String.format(actionMonitor.getGeneratedConfig().replaceAll("^\t+", "")));
}
}
actionMonitor.getGeneratedConfig() is the method that returns the string.
I am trying to write integration test with jersey, Spring boot 1.4 and Spring data jpa.I am able to start embedded server but getting error from jersey side , any help will be appreciated.
Integration test
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes=Application.class)
public class ContactServiceIT {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private ContactDao contactDao;
#Test
public void mergeContactsTest() {
String body = this.restTemplate.getForObject("/contacts/merge", String.class);
assertThat(body).isEqualTo("contacts merged");
}
}
Contact Resource
import java.io.IOException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
#Path("/contacts")
public class ContactResource {
#Autowired
private ContactService contactService;
#GET
#Path("merge")
public Response mergeContacts() throws IOException {
contactService.mergeContacts();
return Response.status(Response.Status.CREATED)
.entity("contacts merged").build();
}
}
Stack trace:
java.lang.NoSuchMethodError: org.glassfish.jersey.CommonProperties.getValue(Ljava/util/Map;Ljavax/ws/rs/RuntimeType;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
at org.glassfish.jersey.jackson.JacksonFeature.configure(JacksonFeature.java:73) ~[jersey-media-json-jackson-2.23.1.jar:na]
at org.glassfish.jersey.model.internal.CommonConfig.configureFeatures(CommonConfig.java:680) ~[jersey-common-2.7.jar:na]
at org.glassfish.jersey.model.internal.CommonConfig.configureMetaProviders(CommonConfig.java:610) ~[jersey-common-2.7.jar:na]
at org.glassfish.jersey.server.ResourceConfig.configureMetaProviders(ResourceConfig.java:800) ~[jersey-server-2.7.jar:na]
Please let me know if I am missing something.
Thanks.
My issue is that, when I call the url http://localhost:8080/site/data/gouv/ with postman with corresponding form data parameters, nothing happens. It seems even the call is not catched by the controller because there is no log.
Postman page
Here is the controller :
package com.mintad.spring.controllers;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.site.common.beans.Gouv;
import com.site.common.service.GouvService;
import au.com.bytecode.opencsv.CSVReader;
#RestController
#RequestMapping("/data")
public class DataController {
#Autowired
private GouvService gouvService;
#RequestMapping(value = "/gouvernorate", method = RequestMethod.POST)
public ResponseEntity<Gouv> addGouvernorate(#RequestBody Gouv gouv) throws IOException {
gouvService.addGouv(gouv);
return new ResponseEntity<Gouv>(gouv, HttpStatus.OK);
}
}
I've tried to call the url with Jsoup as follows :
String base64login = new String(Base64.encode("sof:1".getBytes()));
Document docs = Jsoup.connect("http://localhost:8080/site/data/gouv/").header("Authorization", "Basic " + base64login).
data("name", "name").
data("delegation", "delegation").
data("district", "district").
data("postalCode", "postalCode").post();
But in vain.
Any help please ? I'm using spring security 4.0.4.RELEASE and Spring 4.2.5.RELEASE