Asked  7 Months ago    Answers:  5   Viewed   131 times

I am using Jersey based restful Service implementation strategy to build a service which will be used to upload files. My service class name is : UploadFileService.java (See Code below)

 package com.jerser.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;

@Path("/fileUpload")
public class UploadFileService {

    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFile(
        @FormDataParam("file") InputStream uploadedInputStream,
        @FormDataParam("file") FormDataContentDisposition fileDetail) {

        String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName();

        // save it
        writeToFile(uploadedInputStream, uploadedFileLocation);

        String output = "File uploaded to : " + uploadedFileLocation;

        return Response.status(200).entity(output).build();

    }

    // save uploaded file to new location
    private void writeToFile(InputStream uploadedInputStream,
        String uploadedFileLocation) {

        try {
            OutputStream out = new FileOutputStream(new File(
                    uploadedFileLocation));
            int read = 0;
            byte[] bytes = new byte[1024];

            out = new FileOutputStream(new File(uploadedFileLocation));
            while ((read = uploadedInputStream.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.flush();
            out.close();
        } catch (IOException e) {

            e.printStackTrace();
        }

    }

}

These are the JAR files I have inside my lib:

aopalliance-repackaged-2.4.0-b10.jar     
asm-debug-all-5.0.2.jar     
hk2-api-2.4.0-b10.jar  
hk2-locator-2.4.0-b10.jar     
hk2-utils-2.4.0-b10.jar     
javassist-3.18.1-GA.jar     
javax.annotation-api-1.2.jar     
javax.inject-2.4.0-b10.jar     
javax.servlet-api-3.0.1.jar     
javax.ws.rs-api-2.0.1.jar     
jaxb-api-2.2.7.jar     
jersey-client.jar     
jersey-common.jar     
jersey-container-servlet-core.jar     
jersey-container-servlet.jar     
jersey-core-1.11.jar     
jersey-guava-2.17.jar     
jersey-media-jaxb.jar  
jersey-multipart-1.18.jar    
jersey-server.jar
org.osgi.core-4.2.0.jar
osgi-resource-locator-1.0.1.jar     
persistence-api-1.0.jar    
validation-api-1.1.0.Final.jar

I am getting the following error when I am trying to up my tomcat server :

org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public javax.ws.rs.core.Response com.jerser.service.UploadFileService.uploadFile(java.io.InputStream,com.sun.jersey.core.header.FormDataContentDisposition) at index 0.; source='ResourceMethod{httpMethod=POST, consumedTypes=[multipart/form-data], producedTypes=[], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class com.jerser.service.UploadFileService, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor@d3e2d4]}, definitionMethod=public javax.ws.rs.core.Response com.jerser.service.UploadFileService.uploadFile(java.io.InputStream,com.sun.jersey.core.header.FormDataContentDisposition), parameters=[Parameter [type=class java.io.InputStream, source=file, defaultValue=null], Parameter [type=class com.sun.jersey.core.header.FormDataContentDisposition, source=file, defaultValue=null]], responseType=class javax.ws.rs.core.Response}, nameBindings=[]}']
    at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:528)
    at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:166)
    at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:327)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289)
    at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:286)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:324)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:338)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:171)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:363)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1176)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1102)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1009)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4885)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5212)
    at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5207)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Over the internet I found there are plenty of example which shows How to upload MULTIPART file using RESTFul API. But with same solution. I am not able to run those code as well. I think I am doing something wrong with the JAR files. Could anyone please help me on this?

 Answers

92

Get rid of jersey-multipart-1.18.jar. That is for Jersey 1.x. Add these two

  • jersey-media-multipart-2.17
  • mimepull-1.9.3

For Maven you would use the following dependency (you don't need to explicitly add the mimepull dependency, as this one will pull it in).

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>2.17</version> <!-- Make sure the Jersey version matches
                                 the one you are currently using -->
</dependency>

Then you need to register the MultiPartFeature. If you are using a ResourceConfig for configuration, you can simply do

register(MultiPartFeature.class);

If you are using web.xml, then you can add the class as an <init-param> to the Jersey servlet

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>

Note that if you have multiple providers that you want to register, then you can delimit each provider class with a comma, semicolon, or space/newline. You cannot use this same param-name twice. See Suarabh's answer

UPDATE

Also, once you get rid of jersey-multipart-1.18.jar you will have compile errors for the missing imported classes. For the most part, the class names are still the same, just the packages have changed, i.e.

  • org.glassfish.jersey.media.multipart.FormDataParam
  • org.glassfish.jersey.media.multipart.FormDataContentDisposition

For Dropwizard

If you're using Dropwizard, instead of adding the jersey-media-multipart, they document for your to add dropwizard-forms instead. And instead of registering the MultiPartFeature, you should register the MultiPartBundle

@Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
    bootstrap.addBundle(new MultiPartBundle());
}

Really doesn't make much difference though as all the Dropwizard bundle does is register the MultiPartFeature with the ResourceConfig.


Aside

If you are here for a different ModelValidationException, here are some links for information on other causes of the exception.

  • 1
  • 2
  • 3
Tuesday, June 1, 2021
 
Nate
answered 7 Months ago
37

You can fix the errors by validating your input, which is something you should do regardless of course.

The following typechecks correctly, via type guarding validations

const DNATranscriber = {
    G: 'C',
    C: 'G',
    T: 'A',
    A: 'U'
};

export default class Transcriptor {
    toRna(dna: string) {
        const codons = [...dna];
        if (!isValidSequence(codons)) {
            throw Error('invalid sequence');
        }
        const transcribedRNA = codons.map(codon => DNATranscriber[codon]);
        return transcribedRNA;
    }
}

function isValidSequence(values: string[]): values is Array<keyof typeof DNATranscriber> {
    return values.every(isValidCodon);
}
function isValidCodon(value: string): value is keyof typeof DNATranscriber {
    return value in DNATranscriber;
}

It is worth mentioning that you seem to be under the misapprehention that converting JavaScript to TypeScript involves using classes.

In the following, more idiomatic version, we leverage TypeScript to improve clarity and gain stronger typing of base pair mappings without changing the implementation. We use a function, just like the original, because it makes sense. This is important! Converting JavaScript to TypeScript has nothing to do with classes, it has to do with static types.

const DNATranscriber = {
    G: 'C',
    C: 'G',
    T: 'A',
    A: 'U'
};

export default function toRna(dna: string) {
    const codons = [...dna];
    if (!isValidSequence(codons)) {
        throw Error('invalid sequence');
    }
    const transcribedRNA = codons.map(codon => DNATranscriber[codon]);
    return transcribedRNA;
}

function isValidSequence(values: string[]): values is Array<keyof typeof DNATranscriber> {
    return values.every(isValidCodon);
}
function isValidCodon(value: string): value is keyof typeof DNATranscriber {
    return value in DNATranscriber;
}

Update:

Since TypeScript 3.7, we can write this more expressively, formalizing the correspondence between input validation and its type implication using assertion signatures.

const DNATranscriber = {
    G: 'C',
    C: 'G',
    T: 'A',
    A: 'U'
} as const;

type DNACodon = keyof typeof DNATranscriber;
type RNACodon = typeof DNATranscriber[DNACodon];

export default function toRna(dna: string): RNACodon[] {
    const codons = [...dna];
    validateSequence(codons);
    const transcribedRNA = codons.map(codon => DNATranscriber[codon]);
    return transcribedRNA;
}

function validateSequence(values: string[]): asserts values is DNACodon[] {
    if (!values.every(isValidCodon)) {
        throw Error('invalid sequence');    
    }
}
function isValidCodon(value: string): value is DNACodon {
    return value in DNATranscriber;
}

You can read more about assertion signatures in the TypeScript 3.7 release notes.

Monday, June 28, 2021
 
ALH
answered 6 Months ago
ALH
57

If you project is using org.glassfish, you are using Jersey 2. com.sun is Jersey 1, and you should never mix the two. That being said, the error you are facing is most likely due to the fact that you didn't register the MultipartFeature. When the resource model (the resource methods) are being validated for "correctness" at startup, if the feature is not registered, the annotations specific to this feature is unknown, and it's like just having no annotation. And you cant have more than one method param with no annotation.

If you are using a ResourceConfig, you can simply use

public class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(MultiPartFeature.class);
    }
}

If you are using web.xml, then can set an <init-param> for the Jersey servlet you registered

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>

"I also want to add another String parameter for the web service. What should I do?"

You will need to make that as part of the multipart request and the client needs to make sure to send it as part of the multipart also. On the server side just add another @FormDataParam("anotherString") String anotherString as a method parameter. As for the client, I don't know jQuery that will to help with that. Haven't tested, but you can try this, which shows data being appended to FormParam. Here's something with Angular, where I built the request body myself. Might be a little much, as you may not need to explicitly set the content types.

Saturday, July 31, 2021
 
tsmbl
answered 5 Months ago
31

In order to use multipart in your Jersey application you need to register MultiPartFeature in your application, i.e.:

public class ApplicationConfig extends Application {

    public Set<Class<?>> getClasses() {
        final Set<Class<?>> resources = new HashSet<Class<?>>();

        // Add your resources.
        resources.add(UploadFileService.class);

        // Add additional features such as support for Multipart.
        resources.add(MultiPartFeature.class);

        return resources;
    }
}

For more information see Multipart section in the Jersey Users Guide.

For the second issue you're facing try to restart the GlassFish server, I am not sure how NetBeans are reloading the Jersey app after a change (if this doesn't help, please post your ApplicationConfig).

Sunday, August 1, 2021
 
Nopiforyou
answered 5 Months ago
53

Judging by your code you are basically getting all the values from properties JSON. The reason you are getting that error is because the data has as type {}, because you do not specify it in the generic get<T = {}>() method.

A bit of rewriting would result in this:

getAllProperties(): Observable<IProperty[]>{
  return this.http.get<Record<string, IProperty>>('data/properties.json').pipe(
    map(data => Object.values(data));
  };
}

And you'll be good to go.

Sunday, August 29, 2021
 
sebnukem
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share