I have RESTful service based on Jersey 1.18.1 and I want to show my API via Swagger.
Firstly I have to get JSON. I read this instruction: Swagger Core Jersey 1.X Project Setup 1.5. Swagger allows to set up a configuration different methods and I decided to use custom Application subclass. I did everything step by step but I can't get JSON which I have to use for swagger-ui.
What I did:
My custom Application
#ApplicationPath("api/v1")
public class DiscountsApp extends Application{
public DiscountsApp() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.2");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("localhost:8002");
beanConfig.setBasePath("swaggerapi");
beanConfig.setResourcePackage("alexiuscrow.diploma.endpoints");
beanConfig.setScan(true);
}
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet();
resources.add(ShopsResources.class);
//...
resources.add(com.wordnik.swagger.jaxrs.listing.ApiListingResource.class);
resources.add(com.wordnik.swagger.jaxrs.listing.SwaggerSerializers.class);
return resources;
}
}
ShopsResources
#Path("/shops")
#Api(value="/shops", description="Shops")
public class ShopsResources {
#GET
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(value = "List shops", httpMethod = "GET",
notes = "List nearest or locality shops",
response = Shops.class, responseContainer = "List")
public String getShops(
#ApiParam( value = "Radius", required = false)
#QueryParam("radius") String radiusParam,
#ApiParam( value = "Latitude", required = true)
#QueryParam("lat") String latParam,
#ApiParam( value = "Longitude", required = true)
#QueryParam("lng") String lngParam) throws SQLException{
//The list of Shops objects is serialized to string
//using the custom GSON serializer and I know
//that there is the better method of the solution of this task.
}
}
}
Some dependencies from pom.xml
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-jersey-jaxrs</artifactId>
<version>1.5.1-M2</version>
</dependency>
After deploy application to Tomcat I tried to get http://localhost:8002/swaggerapi but I've got no result.
I didn't find the swagger.json in root of my application (/tomcat8/webapps/app).
What's wrong?
How can I get JSON with my API?
I did not correctly build the url.
Correct:
http://{host}:{port}/{context root of application}/{path from #ApplicationPath}/swagger.json
In my case: http://localhost:8080/app/api/v1/swagger.json
Thx to Ron.
adding a relative path worked for me (this is using .netcore 1.1)
app.UseSwaggerUI(s => {
s.RoutePrefix = "help";
s.SwaggerEndpoint("../swagger/v1/swagger.json", "MySite");
s.InjectStylesheet("../css/swagger.min.css");
});
Related
I'm trying to contract test a Flux of events emitted from an endpoint using Spring Cloud Stream and Spring Cloud Contract. However, I'm getting an IllegalArgumentException with detailMessage Message must not be null when running my test. Or in other words I'm not receiving any messages on my message receiver. My spring cloud version is Hoxton. I've added the following dependencies in my pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>
<!--TEST -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<type>test-jar</type>
<scope>test</scope>
<classifier>test-binder</classifier>
</dependency>
I've configured a new binding following the samples here. Is working properly when I run the app and I send a curl -X POST localhost:8080 request.
application.properties
stubrunner.stream.enabled=true
spring.cloud.stream.bindings.uppercase-in-0.destination=test
spring.cloud.stream.bindings.uppercase-in-0.group=testGroup
spring.cloud.stream.bindings.uppercase-out-0.destination=hood
spring.cloud.stream.bindings.consume-in-0.destination=hood
spring.cloud.stream.bindings.consume-out-0.destination=downtown
spring.cloud.stream.bindings.supplier-out-0.destination=test
spring.cloud.function.definition=uppercase;consume;supplier
Controller
#PostMapping(value = "/")
public void handlePost() {
Faker faker = new Faker();
Message<String> message = MessageBuilder.withPayload(faker.chuckNorris().fact()).build();
// supplier.get();
EventSupplier.processor.onNext(message);
}
Bean definition
#Configuration
public class EventSupplier {
public static final EmitterProcessor<Message<String>> processor = EmitterProcessor.create();
#Bean
// public Supplier<String> supplier() {
public Supplier<Flux<Message<String>>> supplier() {
// return () -> "";
return () -> processor;
}
}
Contracts Base test
#ActiveProfiles("test")
#SpringBootTest
#RunWith(SpringRunner.class)
#AutoConfigureMessageVerifier
#EnableBinding(KafkaStreamerApplication.class)
public abstract class KafkaStreamerApplicationTests {
#Autowired
private DummyController dummyController;
public void supply() {
dummyController.handlePost();
}
}
Contract
org.springframework.cloud.contract.spec.Contract.make {
label 'some_label'
input {
triggeredBy("supply()")
}
outputMessage {
sentTo('supplier-out-0')
body(
anyNonBlankString()
)
headers {
messagingContentType(applicationJson())
}
}
}
I've tried creating contracts for function and consumer and both worked. I've also tried using a supplier of type String instead of Flux<Message<String>> and worked too. You can look at the commented lines at the code above.
While debugging I've seen that in StreamMessageCollectorMessageReceiver I'm getting a DirectWithAttributesChannel instance when retrieving the MessageChannel bean at receive("supplier-out-0", 5, "SECONDS") method. Also while looking into the documentation I've found a MessageChannel implementation that, to me, looks like a candidate to be the one should have been instantiated FluxMessageChannel.
My guess is that spring cloud contract is waiting for a message to be sent into the queue directly(DirectWithAttributesChannel) but since the flux is already in the queue and I'm just updating the flux content, it means that not message is pushed into the queue(FluxMessageChannel?) so no message is received(null) and that's why I'm getting an IllegalArgumentException with details Message must not be null error when running my tests.
Is there something missing in my configuration? Can this scenario be tested by contracts? Is a bad approach to test this by using contracts?
I am using Jersey version 2.29 /java 1.8 on tomcat version 8.5 and trying to retrurn the hasmap<String,String> from jersey rest post service call.
I am getting below exception on server when it is trying to write the hasmap in response.
Aug 23, 2019 10:20:47 PM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=application/xml, type=class java.util.LinkedHashMap, genericType=java.util.Map.
Below are the details of pom.xml,server and jersey client side code.
pom.xml
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version> </dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>${jersey.version}</version>
</dependency>
Client Code
ClientConfig configuration=new ClientConfig();
Client restClientConfig = ClientBuilder.newClient(configuration);
WebTarget webTarget=restClientConfig.target("http://localhost:8080/messenger/webapi/messages/testMap");
HashMap<String,String> mapStr=new HashMap<String,String>();
mapStr.put("a","1");
mapStr.put("b","2");
webTarget.request()
.accept(MediaType.APPLICATION_XML)
.post(Entity.json(mapStr));
Map<String,String> responseMap = new HashMap<String,String>();
GenericType<Map<String,String>> entity = new GenericType<Map<String,String>>() {};
Response xmlResponse = Response.ok(entity).build();
System.out.println("XMLResponse Is :" + xmlResponse + ":"+ responseMap.size());
Jersey Post Service code
#POST
#Path("/testMap")
#Produces(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
#Consumes(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Map<String,String> postMapMessage(Map<String,String> mapMessage) {
System.out.println("It is been invoked....and this time we will add the new MapMessage");
if(mapMessage!=null)
{
System.out.println("Size of the Map Message:" + mapMessage.size());
mapMessage.put("c","3");
}
return mapMessage;
}
I have tried several solutions found on internet but nothing seems to be working for this.
Can anybody please tell me what wrong I am doing in above code snippet?
I am able to partially fix the issue by creating the below wrapper class.
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class JaxrsMapWrapper<T,K> {
private Map<T,K> map;
public JaxrsMapWrapper(){
}
#Override
public String toString() {
return map .toString();
}
public void setMap(Map<T,K> map) {
this.map = map;
}
public Map<T,K> getMap() {
return map;
}
}
By using the above class below getservice returning the typeof Map is working absolutly fine.
#GET
#Path("/mapWarpperReceive")
#Produces({MediaType.APPLICATION_XML})
public JaxrsMapWrapper<String,String> getWarpperMapMsgStr()
{
System.out.println("Returning the MapMessage as String ");
Map<String,String> originalMap=new HashMap<String,String>(){{put("a","a");put("b","b");}};
JaxrsMapWrapper<String,String> jaxRsMapWrapper=new JaxrsMapWrapper<>();
jaxRsMapWrapper.setMap(originalMap);
return jaxRsMapWrapper;
}
But when I am trying to use the same class JaxrsMapWrapper with type of Map it is throwing Error 500 Internal server error while invoking through postman.
#GET
#Path("/customMap")
#Produces({MediaType.APPLICATION_XML})
public JaxrsMapWrapper<String,BookBo> getWarpperMapMsgWithCustomObject()
{
System.out.println("Returning the MapMessage as String and Custom Message ");
Map<String,BookBo> originalMap=new HashMap<>();
originalMap.put("a",new BookBo(1,"Jinesh"));
JaxrsMapWrapper<String,BookBo> jaxRsMapWrapper=new JaxrsMapWrapper();
jaxRsMapWrapper.setMap(originalMap);
return jaxRsMapWrapper;
}
Below is the code for the User defined Java Object BookBo.
#XmlRootElement
public class BookBo implements Serializable{
private Integer id;
private String name;
public BookBo() {
}
public BookBo(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
//getters and setters of the field
}
What am I missing in the above code due to which while writing the Map in response is not working?
So I am trying to implement a simple Jersey Client that hits a public API to get movie times etc..
https://api.eventcinemas.co.nz/Api/Movies/GetMovies
I have gone through tutorials on how to do this and have implemented two methods that deserialzse the JSON response into:
A String
An Object (POJOs)
The issue is this: the JSON to String method is working correctly, printing the String to console gives me the expected result. However when trying to deserialize to my Java Objects I am always getting null.
I have tried a few simple things such as different dependency versions, different API calls etc but no luck. To save time I have used an online converter to take the JSON response and populate the necessary POJOs for deserialization, I have taken this to be correct.
Would someone be kind enough to point me in the right direction on why I am always getting null, I feel like its something small or silly that I have missed. Thanks in advance!
So starting with my pom.xml dependencies...
pom.xml
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
My Client is as follows:
MoviesClient:
package nz.co.brownbridge.application;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
public class MoviesClient {
protected MoviesResponse getMovieDetails() {
/*JSON to POJO*/
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("https://api.eventcinemas.co.nz/Api/Movies/GetMovies");
MoviesResponse response = webTarget.request().accept(MediaType.APPLICATION_JSON_TYPE).get(MoviesResponse.class);
return response;
}
protected String getMovieDetailsString() {
/*JSON to String*/
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("https://api.eventcinemas.co.nz/Api/Movies/GetMovies");
String response = webTarget.request().accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
return response;
}
}
and finally the main() class:
Application Class:
package nz.co.brownbridge.application;
public class Application {
public static void main(String[] args) throws InterruptedException {
MoviesClient moviesClient = new MoviesClient();
String stringResponse = moviesClient.getMovieDetailsString();
MoviesResponse pojoResponse = moviesClient.getMovieDetails();
System.out.println("Printing String Response...");
System.out.println();
System.out.println(stringResponse);
System.out.println();
System.out.println();
System.out.println("Printing POJO Response...");
System.out.println();
System.out.println(pojoResponse);
}
}
Would output the following:
Printing String Response...
//super long but correct string response goes here
Printing POJO Response...
ClassPojo [Data = null, Success = null]
I am trying to add Swagger support to my REST API but I am confused how to add Swagger related static content (HTML, JS) files to my Spring Boot application.
I use the following dependencies:
spring-boot-starter-parent:2.0.1.RELEASE
spring-boot-starter-jersey:2.0.1.RELEASE
swagger-jersey2-jaxrs:1.5.18
This is my swagger configuration:
#Configuration
public class SwaggerConfig {
#Bean
public BeanConfig swaggerConfiguration() {
final BeanConfig beanConfig = new BeanConfig();
beanConfig.setResourcePackage("a.b.c");
beanConfig.setScan(true);
beanConfig.setPrettyPrint(true);
return beanConfig;
}
}
And the jersey configuration:
#Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(ImageResource.class);
register(io.swagger.jaxrs.listing.ApiListingResource.class);
register(io.swagger.jaxrs.listing.SwaggerSerializers.class);
}
}
This part works like a charm, when I open http://localhost:8090/swagger.json then I can see the expected Swagger JSON content.
But I do not know, how to add the Swagger related static HTML content to my application. I can see that this content is in the springfox-swagger-ui.jar and I can add it to my project as a maven dependency, but how I can unpack the content from this jar?
And what is the proper way to overwrite the default swagger.json URL with my URL in the static Swagger file in order to Swagger show my REST API immediately when I open swagger-ui.html.
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>${swagger-ui.version}</version>
</dependency>
Please, do not include springfox-swagger-ui.jar, it's meant to work with Spring's RestController.
You must have solved it now but it might help others so here's the complete procedure as I was also looking for a tutorial.
I am using Swagger V2 with Spring Boot 2 and it's straightforward 3 step process.
Step 1: Add required dependencies in pom.xml file. The second dependency is optional use it only if you need Swagger UI.
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Step 2: Add configuration class
#Configuration
#EnableSwagger2
public class SwaggerConfig {
public static final Contact DEFAULT_CONTACT = new Contact("Usama Amjad", "https://stackoverflow.com/users/4704510/usamaamjad", "hello#email.com");
public static final ApiInfo DEFAULT_API_INFO = new ApiInfo("Article API", "Article API documentation sample", "1.0", "urn:tos",
DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList<VendorExtension>());
#Bean
public Docket api() {
Set<String> producesAndConsumes = new HashSet<>();
producesAndConsumes.add("application/json");
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(DEFAULT_API_INFO)
.produces(producesAndConsumes)
.consumes(producesAndConsumes);
}
}
Step 3: Setup complete and now you need to document APIs in controllers
#ApiOperation(value = "Returns a list Articles for a given Author", response = Article.class, responseContainer = "List")
#ApiResponses(value = { #ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
#GetMapping(path = "/articles/users/{userId}")
public List<Article> getArticlesByUser() {
// Do your code
}
Usage:
Swagger UI: You can access it via http://localhost:8080/swagger-ui.html
Postman: You can also access your Documentation JSON from http://localhost:8080/v2/api-docs and just copy paste it in Postman to use with it.
Am trying to populate a DTO from a published RESTful URL (simple HTTP GET) by using Spring's RestTemplate HTTP Client.
This is the content of the published JSON that I am trying to consume:
[{"startDate":"2017-01-29","cost":"$50000.00","id":1112,"name":"Porsche"},{"startDate":"2017-03-06","cost":"$27000.00","id":38626,"name":"BMW"}]
My DTO:
class DTO {
private String startDate;
private String cost;
private String name;
// Getters and Setters
}
My Response Object:
public class Response {
private static final STRING = "http://www.sample.com/product";
public static List<Object> getCampaigns() {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Object[]> responseEntity = (ResponseEntity) restTemplate.getForEntity(URL, Object[].class);
Object[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();
return Arrays.asList(objects);
}
public void static main (String args []) {
List<Object> dtos = getCampaigns();
for (Object dto : dtos) {
System.out.println(dto.toString());
}
}
}
Here's my pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.7</version>
</dependency>
</dependencies>
When I run the main() method inside Response, I get the following exception:
00:24:14.191 [main] DEBUG org.springframework.web.client.RestTemplate - GET request for "http://www.sample.com/product" resulted in 200 (OK)
Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class [Ljava.lang.Object;] and content type [application/json;charset=utf-8]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:312)
What am I possibly doing wrong?
Try this
public class Response {
private static final String URL = "http://www.sample.com/product";
public static List<DTO> getCampaigns() {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<DTO[]> responseEntity = restTemplate.getForEntity(URL, DTO[].class);
DTO[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();
return Arrays.asList(objects);
}
public void static main (String args []) {
List<DTO> dtos = getCampaigns();
for (DTO dto : dtos) {
System.out.println(dto.toString());
}
}
}
use this jackson library instead
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>