how to use multipart/form-data in spring mvc - java

#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Path("/uploadFile")
public POSResponse singleSave(#FormDataParam("file") MultipartFile file) {
Response response = new Response();
String fileName = null;
if (!file.isEmpty()) {
try {
fileName = file.getOriginalFilename();
byte[] bytes = file.getBytes();
BufferedOutputStream buffStream = new BufferedOutputStream(new FileOutputStream(new File("d:\\" + fileName)));
buffStream.write(bytes);
buffStream.close();
} catch (Exception e) {
}
} else {
}
return response;
}
when i hit this api then i got the error "415: Unsupported Media Type"
this means not supported header.I want to load file from ARC to controller.
and my console:
A message body reader for Java class org.springframework.web.multipart.MultipartFile, and Java type interface org.springframework.web.multipart.MultipartFile, and MIME media type multipart/form-data; boundary=----WebKitFormBoundaryP1d7Atv9FO9wU301 was not found.
The registered message body readers compatible with the MIME media type are:
/ ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
i have add some maven dependency in pom.xml file.
My pom file:
<!-- multipart file dependency -->
<dependency>
<groupId>org.jvnet</groupId>
<artifactId>mimepull</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.jvnet.mimepull</groupId>
<artifactId>mimepull</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>1.17.1</version>
</dependency>

I am not sure about the code which you have written but this how i did it in spring-mvc
Use case: uploading Images
Add a bean definition in our web application's context configuration file
(DispatcherServlet-context.xml) for CommonsMultipartResolver,
as follows:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10240000"/>
Add dependency to pom.xml
enter Group Id as commons-fileupload, Artifact Id as commons-fileupload, Version as 1.2.2; select Scope as compile; and click on the OK button.
Similarly, add one more Group Id dependency as org.apache.commons, Artifact
Id as commons-io, Version as 1.3.2; select Scope as compile; click on the OK
button; and save the pom.xml file
Add a reference to
org.springframework.web.multipart.MultipartFile with the
corresponding setters and getters in the java class the defines the file as a property as follows:
#JsonIgnore
private MultipartFile productImage;
#XmlTransient
public MultipartFile getProductImage() {
return productImage;
}
public void setProductImage(MultipartFile productImage) {
this.productImage = productImage;
}
In the jsp where the file is to be uploaded use the following tag
Set the enctype attribute to multipart/form-data in the form tag as
follows in the jsp
Note: I am using spring form tag libraries
<form:form modelAttribute="newProduct" class="form-horizontal" enctype="multipart/form-data">
Add the following code to the controller
public String processAddNewProductForm(#ModelAttribute("newProduct") #Valid Product productToBeAdded, BindingResult result, HttpServletRequest request) {
if(result.hasErrors()) {
return "addProduct";
}
MultipartFile productImage = productToBeAdded.getProductImage();
String rootDirectory = request.getSession().getServletContext().getRealPath("/");
if (productImage!=null && !productImage.isEmpty()) {
try {
productImage.transferTo(new File(rootDirectory+"resources\\images\\"+productToBeAdded.getProductId() + ".png"));
} catch (Exception e) {
throw new RuntimeException("Product Image saving failed", e);
}
}
productService.addProduct(productToBeAdded);
return "redirect:/products";
}
****Prerequisites****
spring project has been setup correctly, wiring is done
few annotations and lines of code are specific to my project and may not be totally relevant

Related

Retrive bad mimetype with tika (application/x-tika-ooxml)

With docx files, i retrieve application/x-tika-ooxml, but i should retrieve application/vnd.openxmlformats-officedocument.wordprocessingml.document instead
Here is my method :
public String retrieveMimeType(InputStream stream) throws IOException, TikaException {
TikaInputStream tikaStream = null;
TikaConfig tikaConfig = new TikaConfig();
MediaType mediaType = null;
try {
mediaType = tikaConfig.getDetector().detect(TikaInputStream.get(stream), new Metadata());
} catch (Throwable t) {
throw t;
} finally {
if (tikaStream != null) {
try {
tikaStream.close();
} catch (IOException e) {
}
}
}
return mediaType.toString();
}
And my dependecies :
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.27</version>
</dependency>
I use tika-core, and tika-parsers for retrieve the right mimetype, but it still give me the bad mimetype...
Update your tika modules. The version of tika-core and it's modules should always be the same.
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-package</artifactId>
<version>2.1.0</version>
</dependency>
The new microsoft document formats (docx, xlsx, ...) are just zip archives from the outside. Older tika versions will not look into them by default, which is why, depending on the version, they will detect them as either application/zip or application/x-tika-ooxml. You can read more about this here.
Analyzing the archives however can result in a decrease in performance. To prevent this you could, depending on your use case, determine the mime type by name (see below) or use existing mime types like the Content-Type header.
final Metadata metadata = new Metadata();
metadata.add(TikaCoreProperties.RESOURCE_NAME_KEY, fileName);
detector.detect(stream, metadata);
In a HTTP request the file name might also be in the Content-Disposition header.

Spring boot RestTemplate post giving 400 error

I've written a simple webService in Java 8, on Eclipse Photon, using RestTemplate to post (using postForObject) an object (called patentListWrapper) that wraps a List of objects (called PatentDetails ). I post from a Java client (called MainWsClient ) , then set a value in patentDetails on the server side and read the patentListWrapper object back at the client. It works fine when the server side (program SpringWebServiceHello) uses old Spring MVC 4 technology with only 1 jar file (Spring-web.5.07.RELEASE.jar) following this - serverSideExample ie a web.xml and rest-servlet.xml files controlling the access point. I then wrote another server side program (PndGuidRequestWs) using SpringBoot 2.03 with Spring 5.07 jars, and Maven ,with an identicle #RequestMapping method but no web.xml file and the access point defined in the application.properties file:
server.port=8082
server.servlet.path=/
#spring.mvc.servlet.path=/
#server.servlet.contextPath=/
When I call this new server program using this client - ARC it also works fine
but when I call it using the same java client and exactly the same request (accept for a different url obviously). I get a 400 error:
2018-12-18 16:56:53,861 [main] INFO - Running MainWsClient with name = DS fileType = post3
2018-12-18 16:56:54,101 [main] DEBUG - Created POST request for "http://localhost:8082/guidRequest/xmlList"
2018-12-18 16:56:54,145 [main] DEBUG - Setting request Accept header to [application/xml, text/xml, application/json, application/*+xml, application/*+json]
2018-12-18 16:56:54,152 [main] DEBUG - Writing [com.springservice.client.PatentListWrapper#4ba2ca36] using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#3444d69d]
2018-12-18 16:56:54,384 [main] DEBUG - POST request for "http://localhost:8082/guidRequest/xmlList" resulted in 400 (null); invoking error handler
2018-12-18 16:56:54,387 [main] ERROR - DS1B org.springframework.web.client.HttpClientErrorException: 400 null
The non working ,PndGuidRequestWs, server side has:
#RestController
public class PndController {
#RequestMapping(value = "/guidRequest/xmlList", method = RequestMethod.POST, produces = { "application/xml" } )
public PatentListWrapper guidSearchList(#RequestBody PatentListWrapper patentListWrapper) {
for (PatentDetails pd : patentListWrapper.getPatentList())
{
pd.setGuid("guidSetOnServer3");
}
return patentListWrapper;
}
}
The working (SpringWebServiceHello) server side is identicle except for :
value = "/service/greeting/xml/post2"
The Java client has:
public void runCode(String name , String fileType)
{
String url;
if (fileType.equalsIgnoreCase("post2")) {
url = "http://localhost:8080/SpringWebServiceHello/service/greeting/xml/post2";
// This method is identicle to postToPndGuidRequestWs() but this method works fine.
postToSpringWebServiceHello(url);
}else if (fileType.equalsIgnoreCase("post3")) {
url = "http://localhost:8082/guidRequest/xmlList";
// This method gives 404 error
postToPndGuidRequestWs(url);
}
}
private void postToPndGuidRequestWs(String url)
{
PatentListWrapper patentListWrapper = new PatentListWrapper();
PatentDetails pd = new PatentDetails("CN","108552082","A","00000000",12345,"guidIn");
List<PatentDetails> patentList = new ArrayList<PatentDetails>();
patentList.add(pd);
patentListWrapper.setPatentList(patentList);
RestTemplate restTemplate = new RestTemplate();
/* HttpHeaders headers = new HttpHeaders();
headers.add("header_name", "header_value");
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<PatentListWrapper> request = new HttpEntity<PatentListWrapper>(patentListWrapper, headers); */
/*List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
Jaxb2RootElementHttpMessageConverter jaxbMessageConverter = new Jaxb2RootElementHttpMessageConverter();
List<MediaType> mediaTypes = new ArrayList<MediaType>();
mediaTypes.add(MediaType.APPLICATION_XML);
jaxbMessageConverter.setSupportedMediaTypes(mediaTypes);
messageConverters.add(jaxbMessageConverter);
restTemplate.setMessageConverters(messageConverters);*/
/* headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_XML));
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);*/
try {
patentListWrapper = restTemplate.postForObject(
url,
patentListWrapper,
PatentListWrapper.class);
logger.debug("DS1A employee obj returned. guid = " + patentListWrapper.getPatentList().get(0).getGuid());
}catch(Exception e) {
logger.error("DS1B " + e);
}
}
}
ie fileType="post2" calls SpringWebServiceHello, fileType="post3" calls PndGuidRequestWs. As you can see i've tried several commented out solutions but nothing works. Since the only real difference between the 2 server side programs is that none working one uses Spring boot and the working one doesn't the problem must be in the SpringBoot setup ie directory structure, application.properties or pom.xml. My pom.xml has:
<?xml version="1.0" encoding="UTF-8"?>
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>com.clarivate</groupId>
<artifactId>pndguidrequestws</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>pndGuidRequestWs</name>
<description>Guid request webService</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<start-class>com.clarivate.pndguidrequestws.PndGuidRequestWsApplication</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.1.0</version>
<!-- <scope>provided</scope> --> <!-- DS insert for unix -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Implementing XML Representation for Spring Boot Services -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- httpcomponents jars are Required by PndGuidGenerator -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>
<finalName>PndGuidRequestWs</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>
The PatentListWrapper class is:
package com.clarivate.pndguidrequestws.model;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class PatentListWrapper {
private List<PatentDetails> patentList;
public PatentListWrapper() {}
public List<PatentDetails> getPatentList() {
return patentList;
}
public void setPatentList(List<PatentDetails> patentList) {
this.patentList = patentList;
}
}
Any suggestions most welcome.
EDIT:
To simplify the object I created PatentListWrapper2 with just 1 string member:
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class PatentListWrapper2 {
private String name;
public PatentListWrapper2() {}
public PatentListWrapper2(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I can again successfully send this xml using the ARC client:
<patentListWrapper2>
<name>DSDS</name>
</patentListWrapper2>
with contentType="application/xml"
but when I try to send patentListWrapper2 from java I get an unmarshalling error:
2018-12-20 09:17:13,931 [main] INFO - Running MainWsClient with name = DS fileType = post4
2018-12-20 09:17:14,166 [main] DEBUG - Created POST request for "http://localhost:8082/guidRequest/xmlList2"
2018-12-20 09:17:14,200 [main] DEBUG - Setting request Accept header to [application/xml, text/xml, application/json, application/*+xml, application/*+json]
2018-12-20 09:17:14,206 [main] DEBUG - Writing [com.springservice.client.PatentListWrapper2#517cd4b] using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#6cc7b4de]
2018-12-20 09:17:14,246 [main] DEBUG - POST request for "http://localhost:8082/guidRequest/xmlList2" resulted in 200 (null)
2018-12-20 09:17:14,248 [main] DEBUG - Reading [com.springservice.client.PatentListWrapper2] as "application/xml;charset=UTF-8" using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter#6cc7b4de]
2018-12-20 09:17:14,255 [main] ERROR - DS2B org.springframework.web.client.RestClientException: Error while extracting response for type [class com.springservice.client.PatentListWrapper2] and content type [application/xml;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class com.springservice.client.PatentListWrapper2]: unexpected element (uri:"", local:"PatentListWrapper2"). Expected elements are <{}patentListWrapper2>; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"PatentListWrapper2"). Expected elements are <{}patentListWrapper2>
EDIT2 I ran pndGuidRequestWs on Eclipse Tomcat , instead of - Run As -> Spring Boot App. The server log is below:
2018-12-20 11:15:45.655 WARN 236 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.clarivate.pndguidrequestws.model.PatentDetails` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('CN'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.clarivate.pndguidrequestws.model.PatentDetails` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('CN') at [Source: (PushbackInputStream); line: 1, column: 98] (through reference chain: com.clarivate.pndguidrequestws.model.PatentListWrapper["patentList"]->java.util.ArrayList[0])
Can you test with :
try {
HttpHeaders headers = new HttpHeaders();
//headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
//headers.setContentType((MediaType.APPLICATION_JSON));
// I comment the code abouve because you did not specify a consumes whitch defines the media types that the methods of
//a resource class or MessageBodyReader can accept. If not specified, a container will assume that any media type is acceptable.
HttpEntity<PatentListWrapper> request = new HttpEntity<>(patentListWrapper, headers);
PatentListWrapper patentListWrapperResult = = restTemplate.exchange(url, HttpMethod.POST, request,PatentListWrapper.class);
logger.debug("DS1A employee obj returned. guid = " + patentListWrapper.getPatentList().get(0).getGuid());
}catch(Exception e) {
logger.error("DS1B " + e);
}
PatentListWrapper is a complex object, not a piece of xml , so the answer is to remove all references to xml ie
Remove #XmlRootElement(name="PatentListWrapper") from PatentListWrapper.
Add jackson-*.jar(s) into the classpath to do the message converting
Change the server side #RequestMapping from :
#RequestMapping(value = "/xmlList", method = RequestMethod.POST , consumes = { "application/xml" }, produces = { "application/xml" })
to
#RequestMapping(value = "/xmlList", method = RequestMethod.POST )
This means that the ARC client now returns JSON (as it's the default return type), even when I send xml, but that's not important as it's just a test tool.
So, when posting objects with RestTemplate in Spring 2, no contentType settings or additional messageConverters are required on the client side , just:
RestTemplate restTemplate = new RestTemplate();
MyObject myObjectReturn = restTemplate.postForObject(url,myObject,MyObject.class);
and on the server side:
#RestController
#RequestMapping(value = "/endPoint", method = RequestMethod.POST)
public MyObject anyMethodName(#RequestBody MyObject myObject) {
//Do stuff to myObject
return myObject;
}

Jersey 2 multipart/form-data issue. InputStream is empty (available=0)

I am facing issue with jersey 2 file upload. Input stream is coming empty to server side. Using jersey 2.21, jackson 2.5.4, spring 4.1.6.RELEASE (for DI only) & spring security 4.0.2.RELEASE for security. Using JDK 1.8.0_25 and Tomcat 8.0.26.
Code:
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.MULTIPART_FORM_DATA)
public SimpleResult categoryImageUpload(
#FormDataParam("file") InputStream file,
#FormDataParam("file") FormDataBodyPart bodyPart) {
return SimpleResult.success("File Uploaded successfully!!!");
}
File Details is coming in FormDataBodyPart, but InputStream is coming empty(available=0).
Jersey configuration:
#ApplicationPath("api-business")
public class BusinessApplicationConfig extends ResourceConfig {
public BusinessApplicationConfig() {
register(RequestContextFilter.class);
register(MultiPartFeature.class);
packages("com.smx.biz.api");
}
}
dependencies in pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.4</version>
</dependency>
<!--Jersey-->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.21</version>
</dependency>
<!-- Jersey + Spring -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.21</version>
</dependency>
Could somebody help with this issue? Am I missing something???
PS: Spring REST file upload code is working well & InputStream is coming. But Jersey code is not working. Using same client side code to test apis.
Working Spring REST api code:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/business/upload", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
ImageItem categoryPhotoUpload(#RequestBody MultipartFile file) {
return uploadService.uploadFile(file);
}
I want to use Jersey for apis & I don't want to use Spring REST.
Could somebody help with this issue?
I found that when you use the #FormDataParam("file") InputStream file method, under the hood the parameter never gets processed because jersey is actually looking for a File. What happens (at least from what i have read so far) is that when the request comes in jersey does some mime checking using the mimepull library and in turn saves the incoming file as a temporary file. The issue is that if your parameter type is InputStream, jersey does not handle it because there is no ValueFactory registered for InputStream. So in order for this to work you have to do the following.
Inside FormDataParamValueFactoryProvider
Add the following implementation:
private final class InputStreamFactory extends ValueFactory<InputStream> {
private final String name;
public InputStreamFactory(final String name) {
this.name = name;
}
#Override
public InputStream provide() {
LOG.info("Processing paramaeter [" + name + "]");
final FormDataBodyPart part = getEntity().getField(name);
final BodyPartEntity entity = part != null ? part.getEntityAs(BodyPartEntity.class) : null;
if (entity != null) {
try {
// Create a temporary file.
final File file = Utils.createTempFile();
// Move the part (represented either via stream or file) to the specific temporary file.
entity.moveTo(file);
//Retreive file via a FileInputStream
return new FileInputStream(file);
} catch (final Exception ex) {
// Unable to create a temporary file or move the file.
LOG.warn("Error while processing InputStream. " + ex);
}
}
return null;
}
}
This will allow jersey to detect the InputStream.
You also have to change the createValueFactory method to reflect the new ValueFactoryProvider.
#Override
protected Factory<?> createValueFactory(final Parameter parameter) {
final Class<?> rawType = parameter.getRawType();
if (Parameter.Source.ENTITY == parameter.getSource()) {
if (FormDataMultiPart.class.isAssignableFrom(rawType)) {
return new FormDataMultiPartFactory();
} else {
return null;
}
} else if (parameter.getSourceAnnotation().annotationType() == FormDataParam.class) {
final String paramName = parameter.getSourceName();
if (paramName == null || paramName.isEmpty()) {
// Invalid query parameter name
return null;
}
if (Collection.class == rawType || List.class == rawType) {
final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);
if (FormDataBodyPart.class == clazz) {
// Return a collection of form data body part.
return new ListFormDataBodyPartValueFactory(paramName);
} else if (FormDataContentDisposition.class == clazz) {
// Return a collection of form data content disposition.
return new ListFormDataContentDispositionFactory(paramName);
} else {
// Return a collection of specific type.
return new FormDataParamValueFactory(parameter, get(parameter));
}
} else if (FormDataBodyPart.class == rawType) {
return new FormDataBodyPartFactory(paramName);
} else if (FormDataContentDisposition.class == rawType) {
return new FormDataContentDispositionFactory(paramName);
} else if (File.class == rawType) {
return new FileFactory(paramName);
} else if (InputStream.class == rawType) {
return new InputStreamFactory(paramName);
} else {
return new FormDataParamValueFactory(parameter, get(parameter));
}
}
return null;
}
Now... here's where it becomes a pain... if you dont pull the module source from github and and compile with the changes.... you have to basically recreate the following classes in order to reference the new class through the reference chain.
Classes:
FormDataParamValueFactoryProvider
FormDataParamInjectionFeature (References: FormDataParamValueFactoryProvider)
MultiPartFeature (References: FormDataParamInjectionFeature)
Once this is done, you can then use #FormDataParam("file") InputStream and it will work as expected.
Make sure that the string inside the annotation
#FormDataParam("theSameStringUsedInAnnotation") InputStream file
exactly matches the name of the resource that you are posting.
In my case I was using ExtJs fileupload and when you define there a fileupload like:
xtype: 'filefield',
name: 'theSameStringUsedInAnnotation',
you have to define the same string
In My case I replaced #FormDataParam("file") InputStream file with #FormDataParam("file") File file then it started working fine.

Can't get json from Swagger + Jersey

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");
});

How to return a XML response from a POST rquest with Spring MVC?

I am making a POST request which sends a JSON. The Controller picks up the JSON, processes the JSON and I want the controller to return some data in XML format.
How can I do that with a POST request?
#RequestMapping( value = Controller.RESOURCE_PATH + ".xml", headers = "Accept=application/json", produces = "*/*" )
public String exportXml( #RequestBody String requestJson ) throws IOException
{
JSONObject json = JSONObject.fromObject( requestJson );
Option option = new Option();
option.processJson( json );
return "";
}
There are many ways to achieve this. One is to use MarshallingView and XStreamMarshaller
Firstly add following jars to your classpath (maven dependencies):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.4</version>
</dependency>
Then configure a Marshaller on your spring xml configuration
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
Assuming you have following bean you want to Marshal (ie: display as XML)
public class MyMessage {
private String message;
// getters & setters
}
In your controller class inject org.springframework.oxm.Marshaller and have your handler method return a MarshallingView like this:
#Controller
public class MyController {
#Autowired private Marshaller marshaller;
#RequestMapping("/helloxml")
public MarshallingView helloxml(Model model) {
MyMessage msg = new MyMessage();
msg.setMessage("hello world");
model.addAttribute("msg", msg);
MarshallingView marshallingView = new MarshallingView(marshaller);
marshallingView.setModelKey("msg"); // set what model attribute to display as xml
return marshallingView;
}
}
The above setup will give you xml like this when /helloxml is requested
<com.gerrydevstory.xmlview.MyMessage>
<message>hello world</message>
</com.gerrydevstory.xmlview.MyMessage>
Of course this isn't a very good setup if you deal with many XML marshalling. You should leverage view resolvers configuration in this case.
Also the name of XML element can be aliased too to shorten it. Check out the XStream documentation
Finally, keep in mind XStream is just one of many marshaller supported by Spring, also consider JAXB, Castor, Jibx etc.

Categories

Resources