Swagger UI not working when Spring controller uses parameter Map - spring-mvc

We are using Swagger and Spring Fox version 2.5.0, POM entry below. When we create a Spring MVC controller that has uses a parameter Map (see example below), then the Swagger-UI page does not properly generate. The controller in question does not appear on the Swagger-UI page and none of the controllers that come after it appear also (in alphabetical order).
#RequestMapping(value = "/resource/", method = RequestMethod.GET, produces = {"application/json"})
public void get(#RequestParam MultiValueMap<String, String> params) {
//code
}
When the params Map is removed, then everything is fine. Any idea what the issue could be or how to get around it?
Below is more info that may or may not be useful.
the dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>
the Swagger config:
#Configuration
#EnableSwagger2
public class SwaggerConfiguration {
#Bean
public Docket api() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.paths(PathSelectors.any())
.build();
docket.ignoredParameterTypes(Principal.class);
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("some app")
.description("some description")
.build();
}
}

Related

How to return Bean class Object as JSON in Rest Controller in Spring MVC

Here my controller is like,
#RequestMapping(value = "/restCallRequest", headers =
"Accept=application/json", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<Void> callRequest(#RequestBody CallRequestData
requestData, UriComponentsBuilder ucBuilder) {
if (requestData.getIvrName().isEmpty()) {
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}
System.err.println("IVER Name is "+requestData.getIvrName()+" lsit "+requestData.getContactList().get(0));
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/restCallRequest").buildAndExpand(requestData).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
And my Bean Class is,
#Entity
public class CallRequestData {
private int id; //Auto incremented
private String ivrName;
private List<String> contactList;
public CallRequestData(int id, String ivrName, List<String> contactList) {
this.id = id;
this.ivrName = ivrName;
this.contactList = contactList;
}
//setters And Getters
Here my POSTMAN send JSON
{
"ivr_name":"welcome",
"contactList":[
"9040210495",
"958045830"
]
}
And Also i want Response as like Request,
{
"ivr_name":"welcome",
"contactList":[
"9040210495",
"958045830"
]
}
How can i solve it. Thanks In Advance.
add dependency in pom.xml
<dependency>
<groupId>net.sf.flexjson</groupId>
<artifactId>flexjson</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
Write one method in controller.
public String toJson(User bean) {
return new JSONSerializer().transform(new DateTransformer("MM/dd/yyyy HH:mm:ss"),java.util.Date.class).serialize(bean);
}
and pass your bean object to this method.
return new ResponseEntity<String>(toJson(bean),headers, HttpStatus.CREATED);
change return type to string in method signature public ResponseEntity<String> callRequest
NOTE: For Spring boot you can use #RestController annotation which will auto convert objects to json.
Add Jackson dependencies
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
<scope>provided</scope>
</dependency>
and add
#RequestMapping(value="/endpoint",produces="application/json",method=RequestMethod.POST)
produces="application/json" to the request mapping. \
Now whatever, bean is defined after #ResponseBody will get returned as a json object to client. There is no need to parse it as json externally.
I don't understand why you make all this option.
Is so easy.
If your controller is annotated with #RestController, you have just to return the object like this:
#RequestMapping..................................)
public ResponseEntity<CallRequestData> callRequest(#RequestBody CallRequestData
requestData, UriComponentsBuilder ucBuilder) {
......... code here ......
return new ResponseEntity<>(requestData, HttpStatus.CREATED);
}
Set the return type on the response entity and then return just return a new instance of ResponseEntity it like this.
I suggest you avoid multiple RETURN, assign a variable to the ResponseEntity and return just once at the end of the method

MockMvc ignores JsonFormat jackson annotation

I set-up a REST API with Spring MVC and Spring HATEOAS.
In one of the DTOs I put a JsonFormat on a ZonedDateTime field.
Running the server gives me the expected date format (yyyyMMdd), but with testing the annotation is ignored and I get something like 1454281200.000000000. So it looks like when testing the annotation is ignored totally. I tried the #JsonIgnore annotation, but that on was working.
No matter I use MockMvcBuilders.webAppContextSetup(wac).build() or MockMvcBuilders.standaloneSetup(membersController).build() the time is simply not converted to the JsonFormat as expected.
Anyone any idea's what going wrong here? I expect some configuration issue, but I don't know where to look at.
Discovered that the aDate on the Resource is serialised properly, but the xxxDTO.aDate is not serialised properly.
Resource
public class XxxResource extends Resource<XxxDTO> {
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd")
private ZonedDateTime aDate;
public XxxResource(XxxDTO xxxDTO) {
super(xxxDTO);
this.aDate = xxxDTO.getADate();
}
}
DTO
public class XxxDTO {
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd")
private ZonedDateTime aDate;
}
pom.xml
<jackson.version>2.8.3</jackson.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.3-RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.20.0.RELEASE</version>
</dependency>
Test setup
#RunWith(MockitoJUnitRunner.class)
public class SomeTest {
XxxController xxxController = new XxxController(XxxService, new XxxResourceAssembler(),
new PagedResourcesAssembler<>(new HateoasPageableHandlerMethodArgumentResolver(), null));
this.mockMvc = MockMvcBuilders.standaloneSetup(xxxController).setCustomArgumentResolvers
(new PageableHandlerMethodArgumentResolver()).build();
}
The endpoints are set up through a web.xml and the WebMvcConfig is like this:
#Configuration
#EnableWebMvc
#EnableSpringDataWebSupport
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new PageableHandlerMethodArgumentResolver());
}
#Bean
public PagedResourcesAssembler pagedResourcesAssembler() {
return new PagedResourcesAssembler(new HateoasPageableHandlerMethodArgumentResolver(), null);
}
}

springfox does not return the api doc

I'm trying to integrate springfox in to my existing sprint web application I configured the springfox the web app is starting correctly but the api doc is not getting generated
here is the springfox configuration class
#EnableSwagger2 //Loads the spring beans required by the framework
public class SwaggerConfig {
#Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
}
here is the bean creation
<bean id="config" class="com.myApp.general.SwaggerConfig"/>
following is the controller
#Controller
public class MyController {
#ApiOperation(value = "Gets architecture services",
notes = "",
produces = "application/json")
#RequestMapping(value = "v1/users", method = RequestMethod.GET)
#ResponseBody
public Object users(HttpServletResponse response) {
//method implementation
}
}
when i try to get the api doc it just returns a 404. can someone help me on this
it may be a late answer..but should help people still looking/searching
anyway the below answer should work .
for html the ui.html handler is needed
and for others webjars/** is needed
uri.startsWith("/swagger")|| uri.startsWith("/webjars")||uri.startsWith("/v2/api-docs");
if you have filter-chain to access-specific url's ,be sure to omit any filter cheking similar to above code
#Component
public class SwaggerConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}....
adding above code makes your spring application to look into the folders for swagger-ui files.
if you already have a resource handler..donot forget to include these there.In this case no need to write a special resource handler

Spring Boot & Thymeleaf with XML Templates

I have a Spring Boot application with a controller that returns a ModelAndView and Thymeleaf to render templates, where the templates live in /src/main/resources/templates/*.html
This works fine, but How can I configure Spring and/or Thymeleaf to look for xml files instead of html?
If it helps, I'm using Gradle with the org.springframework.boot:spring-boot-starter-web dependency to set things up. I am currently running the server using a class with a main method.
After trying and failing at various bean defs for viewResolver and related things, I finally got this working with a change to my application.yaml file:
spring:
thymeleaf:
suffix: .xml
content-type: text/xml
For those reading this later, you can do similar with your application.properties file (with dot notation in place of the yaml indentation).
This works too :
#Configuration
public class MyConfig
{
#Bean
SpringResourceTemplateResolver xmlTemplateResolver(ApplicationContext appCtx) {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(appCtx);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".xml");
templateResolver.setTemplateMode("XML");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCacheable(false);
return templateResolver;
}
#Bean(name="springTemplateEngine")
SpringTemplateEngine templateEngine(ApplicationContext appCtx) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(xmlTemplateResolver(appCtx));
return templateEngine;
}
}
And for the usage
#RestController
#RequestMapping("/v2/")
public class MenuV2Controller {
#Autowired
SpringTemplateEngine springTemplateEngine;
#GetMapping(value ="test",produces = {MediaType.APPLICATION_XML_VALUE})
#ResponseBody
public String test(){
Map<String, String> pinfo = new HashMap<>();
Context context = new Context();
context.setVariable("pinfo", pinfo);
pinfo.put("lastname", "Jordan");
pinfo.put("firstname", "Michael");
pinfo.put("country", "USA");
String content = springTemplateEngine.process("person-details",context);
return content;
}
}
Don't forget the template in resources/templates folder
<?xml version="1.0" encoding="UTF-8"?>
<persons >
<person>
<fname th:text="${pinfo['lastname']}"></fname>
<lname th:text="${pinfo['firstname']}"></lname>
<country th:text="${pinfo['country']}"></country>
</person>
</persons>

Spring MVC integration tests with Spring Security

I'm trying to test my login page using mvc-test.
I was working pretty good before I added spring security.
My code is:
mockMvc.perform(
post("j_spring_security_check")
.param(LOGIN_FORM_USERNAME_FIELD, testUsernameValue)
.param(LOGIN_FORM_PASSWORD_FIELD, testPasswordValue))
.andDo(print())
.andExpect(status().isOk())
.andExpect(model().attribute(LOGIN_PAGE_STATUS_VALUE, LOGIN_PAGE_STATUS_FALSE_INDICATOR));
Test class has correct annotations added:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {"classpath:security-context.xml", "classpath:applicationContext.xml", "classpath:test-contexts/test-context.xml" })
My filter is defined (in web.xml):
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
When I try to add web.xml in #ContextConfiguration it fails, when I remove it I'm getting an Exception:
java.lang.AssertionError: Status expected:<200> but was:<405>
Is there any way to add DelegatingProxyFilter to test context with configuration defined in my security-context.xml to make it works? I tried few tutorials with injecting FilterProxyChain, but it is not working in my case.
Can someone help me with that?
Thanks in advance
UPDATE: Spring Security 4+ provides out of the box integration with MockMvc. In order to use it ensure you use apply(springSecurity()) as shown below:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class MockMvcSecurityTests {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
...
}
Original Answer
I'm not sure what you mean by "When I try to add web.xml in #ContextConfiguration it fails", however, you can use Spring Test MVC to validate Spring Security. There is a very good example outlined in the spring-test-mvc project.
The basic outline would look something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {"classpath:security-context.xml", "classpath:applicationContext.xml", "classpath:test-contexts/test-context.xml" })
public class MyTests {
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilters(this.springSecurityFilterChain).build();
}
}
The idea is that you #Autowire the FilterChainProxy (what the DelegatingProxyFilter delegates to) and instruct MockMvc to use the FilterChainProxy.
NOTE spring-test-mvc is integrated into spring-test-3.2+ and a separate project for Spring 3.1.x, so you can use the example fairly interchangeably (spring-test-mvc does not have support for #WebAppConfiguration and has to use WebContextLoader instead).
Add in pom.xml
<repository>
<id>spring-snaspho</id>
<url>http://repo.springsource.org/libs-milestone/</url>
</repository>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.0.M1</version>
</dependency>
and use org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors for authorization request. See the sample usage at https://github.com/rwinch/spring-security-test-blog (https://jira.spring.io/browse/SEC-2592)

Resources