Is it possible to upload attachment in java using REST API without using cURL ?
Is it possible to upload a file using REST API BROWSER ?
Here my code for upload and download attachment :
public boolean addAttachmentToIssue(String issueKey, String fullfilename) throws IOException{ CloseableHttpClient httpclient = HttpClients.createDefault(); HttpPost httppost = new HttpPost(jira_attachment_baseURL+"/api/latest/issue/"+issueKey+"/attachments"); httppost.setHeader("X-Atlassian-Token", "nocheck"); httppost.setHeader("Authorization", "Basic "+jira_attachment_authentication); File fileToUpload = new File(fullfilename); FileBody fileBody = new FileBody(fileToUpload); HttpEntity entity = MultipartEntityBuilder.create() .addPart("file", fileBody) .build(); httppost.setEntity(entity); String mess = "executing request " + httppost.getRequestLine(); logger.info(mess); CloseableHttpResponse response; try { response = httpclient.execute(httppost); } finally { httpclient.close(); } if(response.getStatusLine().getStatusCode() == 200) return true; else return false; } public boolean getAttachmentFromIssue(String contentURI, String fullfilename) throws IOException { CloseableHttpClient httpclient = HttpClients.createDefault(); try { HttpGet httpget = new HttpGet(contentURI); httpget.setHeader("Authorization", "Basic "+jira_attachment_authentication); System.out.println("executing request " + httpget.getURI()); CloseableHttpResponse response = httpclient.execute(httpget); int status = response.getStatusLine().getStatusCode(); if (status >=200 && status < 300) { HttpEntity entity = response.getEntity(); if (entity.isStreaming()) { byte data[] = EntityUtils.toByteArray(entity); FileOutputStream fout = new FileOutputStream(new File(fullfilename)); fout.write(data); fout.close(); } } } finally { httpclient.close(); } return true; }
jira_attachment_authentication is define elsewhere as :
jira_attachment_authentication = new String(org.apache.commons.codec.binary.Base64.encodeBase64((user+":"+pass).getBytes()));
Yes it's possible. For example JIRA REST Java Client does that: https://bitbucket.org/atlassian/jira-rest-java-client/src/bd758b52f53978033bdd0d8071edd75d7bdcc607/core/src/main/java/com/atlassian/jira/rest/client/internal/async/AsynchronousIssueRestClient.java?at=master#
You'll have to send multipart request - the code will depend on HTTP client that you use.
There is already answer for that question here: http://stackoverflow.com/questions/18631361/add-attachment-to-jira-via-rest-api
I copy paste the answer from the stackoverflow.comlink, but some dependencies are missing (MultipartEntity, HttpEntity, ...)
Can you help me ?
if you want to do it through perl then try with this
https://metacpan.org/pod/JIRA::Client::Automated#attach_file_to_issue
you can download dependencies from here
http://hc.apache.org/downloads.cgi
Loïc GRIVEAU, are you able to attach to issues using sample in stackoverflow link?
if yes then can you sahre your code here?
Can you show me your which is getting the file? File fileToUpload = new File(fullfilename); FileBody fileBody = new FileBody(fileToUpload);
THIS CODE WORKS:
public class JiraRest {
public static void main(String[] args) throws ClientProtocolException, IOException { String pathname= "<Full path name of the attachment file>"; File fileUpload = new File(pathname);
HttpClient httpClient = HttpClientBuilder.create().build(); HttpPost postRequest = new HttpPost("URL+Post REST API"); BASE64Encoder base=new BASE64Encoder(); String encoding = base.encode ("username:password".getBytes()); postRequest.setHeader("Authorization", "Basic " + encoding); postRequest.setHeader("X-Atlassian-Token","nocheck");
MultipartEntityBuilder entity=MultipartEntityBuilder.create(); entity.addPart("file", new FileBody(fileUpload)); postRequest.setEntity( entity.build()); HttpResponse response = httpClient.execute(postRequest); } }Required JARs:
All JARs in lib folder of httpcomponents-client-4.5-bin and sun.misc.BASE64Decoder.jar
Loïc GRIVEAU, if I try to use the same code to move attachments from one JIRA instance to another, it gives 415 error. : 415 Unsupported Media Type.
Any idea?
Hi, can you pls share the jar/lib that you used in your program?
This works for me:
const auth = 'Basic ' + new Buffer(props['jiraAppUserName'] + ':' + props['jiraAppPassword']).toString('base64'); var options = {url: 'https://JIRAUAT.xx.xx/rest/api/latest/issue/XEA-1255/attachments',headers: {'Authorization': auth,'X-Atlassian-Token': 'nocheck' } };var r = request.post(options, function (err, res, body) {if (err) {console.error(err); resOut.status(500).json({messages: 'outch',obj: {} }); } else {console.log('Upload successful! Server responded with:', body); resOut.status(200).json({messages: 'successfully updated jira ticket',obj: {} }); } } );var form = r.form();form.append('file', fs.createReadStream('./somefile.png'));
Can you please attach the complete file/code?
Awesome. This worked perfectly..
Where is the ticket URL
?
Sorry I posted this answer more than 3 years back, I don't remember anything as of now
HttpPost postRequest = new HttpPost("URL+Post REST API");
does this mean like this
HttpPost postRequest = new HttpPost("https:/abc.atlassian.net/rest/api/2/issue+https://abc.atlassian.net/browse/MSAM-42?filter=-4");
I managed to make it work with PostMan.
Header must contain:
Content-Type: multipart/form-data
X-Atlassian-Token: no-check
Body must be of type "form-data" and must contain a key named "file" with value a specified file (I had to use the file picker, see the picture).
HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory(parameters);MultipartContent content = new MultipartContent().setMediaType(new HttpMediaType("multipart/form-data").setParameter("boundary", "__END_OF_PART__"));for(Attachment attachment : attachments) { File attachmentFile = ComponentAccessor.getAttachmentManager(). streamAttachmentContent(attachment, new FileInputStreamConsumer(attachment.getFilename())); String mimeType = URLConnection.guessContentTypeFromName(attachmentFile.getName()); FileContent fileContent = new FileContent(mimeType, attachmentFile); MultipartContent.Part part = new MultipartContent.Part(fileContent); part.setHeaders(new HttpHeaders().set("Content-Disposition", String.format("form-data; name=\"file\"; filename=\"%s\"", attachmentFile.getName()))); content.addPart(part);}HttpRequest request = requestFactory.buildPostRequest(jiraUrl, content);request.getHeaders().set("X-Atlassian-Token", "no-check");return request.execute();
Java code using google-http to POST attachments to /rest/api/2/issue/{issueIdOrKey}/attachments using OAuth. Still trying to figure out format for posting attachments on issue create.
What will be body for this endpoint i am using postman and it is not working for me : /rest/api/2/issue/{issueIdOrKey}/attachments
can anyone share postman body.
neither for me.... i have try all
Hi guys ! I've managed to POST attachment via Postman. An example :https://jira-dev.server_url.com/rest/api/2/issue/NOC-618/attachmentsEverything works fine.However, I need to implement via Java service which use OAuth1.First, there is a need to manipulate header, that is, to insert
"X-Atlassian-Token", "no-check"
and then, to upload actual input streams.Any ideas ?
Here's a working method from a Python 3.x module. The key things that aren't spelled out in many solutions:
def add_attachment(self, path): '''Upload a file attachment from a local file path. ''' error_messages = [] try: f = open(path, 'rb') # all files, even plain text, must be read as binary data file_contents = f.read() f.close() except: error_messages.append('cannot read ' + path) if not error_messages: # create multipart/form-data as defined in RFC 1867 (see: https://www.ietf.org/rfc/rfc1867.txt) boundary = binascii.hexlify(os.urandom(16)).decode('ascii') separator = '' # CRLF is the standard separator in multipart/form-data # multipart/form-data consists of: prefix + file contents + suffix prefix = '--{}{}'.format(boundary, separator) prefix += 'Content-Disposition: form-data; name="file"; filename="{}"{}'.format(os.path.basename(path), separator) prefix += 'Content-Type: application/octet-stream{}'.format(separator) prefix += separator suffix = separator + '--{}--{}'.format(boundary, separator) # convert the prefix and suffix text to binary, and then join them around the binary file contents prefix = prefix.encode('utf-8') suffix = suffix.encode('utf-8') data = b''.join([prefix, file_contents, suffix]) headers = {} headers['Content-Type'] = 'multipart/form-data; boundary={}'.format(boundary) headers['X-Atlassian-Token'] = 'no-check' headers['Content-Length'] = str(len(data)) # length must include the entire multipart/form-data, not just the file contents api = 'api/2/issue/' + self.key + '/attachments' (status, response) = self._session._call_api(api, headers=headers, data=data) if not (status >= 200 and status <= 299): error_messages += standard_errors(status, response) return error_messages
Hello;
Do you have sample code for downloading all attachments of all Jira issues reported in a Jira project?
Thank you;
Lily
Thanks, this worked for me.
Hello, just facing problem with UTF-8 characters in file name.When uploading with postman, like in example everything is fine, but when uploading by java API, german umalut characters are converted as ???? Any suggestion?
Hi @Danut M _StonikByte_ , @Ramandeep Singh Nagi ,
I tried to attach the attachment via postman by using your above Info. When I used Content-Type as "multipart/form-data" am getting the below error.
But I removed Content-Type and my postman was successful.
Did I missed anything with "Content-Type" ?
Regards,
Parthiban
Hello Parthiban,
I used the following settings in my Postman:
POST Url:
https://jira.your.url.com/rest/api/latest/issue/ABCD-1234/attachments
Headers:
Content-Type: multipart/form-data,
X-Atlassian-Token: no-check,
charset: UTF-8,
Accept-Encoding: gzip, deflate, br
Body -> form-data:
file: <give path to your file to be attached>
I hope this helps.
Ramandeep Singh
I've done the other way, by pure "spring-like" flow so to speak.Actually, I have a complete git project, however, for the attachment, I still need to add functionality, however, I'll give you fast and dirty solution until I add in project.
For details please visit : https://github.com/dobrivoje/jiraintegration
Here is :REST :..
@POST@Consumes(MediaType.MULTIPART_FORM_DATA)@Produces(MediaType.APPLICATION_JSON)@Path("createIssueWithAttachment")ResponseEntity<ResponseIssueCreationDto> createIssueWithAttachmentStreamForSupport(@FormDataParam("summary") String summary,@FormDataParam("nmeTeam") @NonNull String nmeTeam,@FormDataParam("handOverDate") @NonNull Date handOverDate,@FormDataParam("supportType") @NonNull String supportType,@FormDataParam("description") String description,@FormDataParam("siteAddress") String siteAddress,@FormDataParam("siteContacts") String siteContacts,@FormDataParam("topology") String topology,@FormDataParam("file") InputStream attachment,@FormDataParam("file") FormDataContentDisposition fileDetail,@FormDataParam("file") FormDataBodyPart body);
...
REST implementation :
@Overridepublic ResponseEntity<ResponseIssueCreationDto> createIssueWithAttachmentStreamForSupport( String summary, String nmeTeam, Date handOverDate, String supportType, String description, String siteAddress, String siteContacts, String topology, InputStream attachment, FormDataContentDisposition fileDetail, FormDataBodyPart body) {return ResponseEntity.status( HttpStatus.OK ) .contentType( APPLICATION_JSON ) .body(service.createNocIssueWithStreamAttachmentForSupport( supportType, nmeTeam, handOverDate, siteAddress, siteContacts, topology, description, summary, attachment, fileDetail, body ) );}
Custom service (interface) :
ResponseIssueCreationDto createIssueWithStreamAttachmentForSupport(@NonNull String supportType, @NonNull String nmeTeam, Date handOverDate, String siteAddress, String siteContacts, String topology, String description, String summary, InputStream attachment, FormDataContentDisposition fileDetail, FormDataBodyPart body);
Custom service implementation :
@Overridepublic ResponseIssueCreationDto createIssueWithStreamAttachmentForSupport(String supportType, String nmeTeam, Date handOverDate, String siteAddress, String siteContacts, String topology, String description, String summary, InputStream attachment, FormDataContentDisposition fileDetail, FormDataBodyPart body) { ResponseIssueCreationDto newIssue = createBasicIssueWithoutAttachmentForSupport( supportType, nmeTeam, handOverDate, siteAddress, siteContacts, topology, description, summary ); addAttachmentToIssue( attachment, fileDetail, body, newNocIssue.getIssueKey() );return newNocIssue;}
@Overridepublic ResponseIssueCreationDto createBasicIssueWithoutAttachmentForSupport( String supportType, String nmeTeam, Date handOverDate, String siteAddress, String siteContacts, String topology, String description, String summary) {//<editor-fold desc="Stylized error message, for only missing mandatory fields"> boolean isErrSupportType = supportType == null;boolean isErrNmeTeam = !NocNMETeam.isValidTeam( nmeTeam );boolean isErrHandOverDate = handOverDate == null; String errNew = (isErrSupportType ? "Support type, " : "") + (isErrNmeTeam ? "NME team, " : "") + (isErrHandOverDate ? "Handover date " : ""); String errorMessage = errNew.substring( 0, ((isErrSupportType || isErrNmeTeam) && !isErrHandOverDate) ? errNew.length() - 2 : errNew.length() ).concat( " must be defined." );//</editor-fold> Commons.ensureNonNullsWithMessageFor( errorMessage, supportType, nmeTeam, handOverDate );//<editor-fold desc="Service desk id, and Request type id"> ServiceDesksDto serviceDeskProjectDto = getAllServiceDesks().orElseThrow( () -> new JiraAllServiceDesksException( errorMessage ) ); ServiceDeskProjectDto sdp = serviceDeskProjectDto .getValues() .stream() .filter( p -> JiraNocProjectKey.equalsIgnoreCase( p.getProjectKey() ) ) .findFirst() .orElseThrow( () -> new JiraServiceDeskProjectException( errorMessage ) ); String projectIdStr = Optional.ofNullable( sdp.getId() ).orElseThrow( RuntimeException::new ); ServiceDesksRequestTypeDto serviceDesksReqTypeDto = getServiceDeskWithRequestTypeForDesk( Long.valueOf( projectIdStr ) ) .orElseThrow( () -> new JiraServiceDeskRequestTypeException( errorMessage ) ); ServiceDeskRequestTypeValueItemDto srvDesksReqTypeValDto = serviceDesksReqTypeDto .getValues() .stream() .filter( f -> projectIdStr.equals( f.getServiceDeskId() ) ) .filter( n -> JiraNocSupport.equalsIgnoreCase( n.getName() ) ) .findFirst() .orElseThrow( () -> new JiraServiceDeskRequestTypeValueException( errorMessage ) );//</editor-fold> GenericData rootNodeResult = new GenericData(); rootNodeResult.put( ServiceDeskId, projectIdStr ); rootNodeResult.put( RequestTypeId, srvDesksReqTypeValDto.getId() ); GenericData childrenRequestFieldValues = new GenericData(); Date hoDate3BDays = DateUtil.getEndBusinessDayFor( handOverDate, 3 ); String hoDate = new SimpleDateFormat( JIRA_MISTERY_DATETIME_PATTERN2 ).format( hoDate3BDays ); childrenRequestFieldValues.put( REQIRED_BY_DATE, hoDate ); childrenRequestFieldValues.put( SITE_ADDRESS, Commons.getFieldWithValidLengthOf255( siteAddress ) ); childrenRequestFieldValues.put( SITE_CONTACTS, siteContacts ); childrenRequestFieldValues.put( TOPOLOGY, topology ); childrenRequestFieldValues.put( SUMMARY, summary ); childrenRequestFieldValues.put( DESCRIPTION, description ); GenericData childReqNMETeam = new GenericData();try { childReqNMETeam.put( "value", NocNMETeam.getValidCode( nmeTeam ) ); childrenRequestFieldValues.put( NME_TEAM, childReqNMETeam ); } catch (UnsupportedOperationException nte) {throw new JiraNOCTeamException( NocNMETeam.getValidTeams(), JIRA_HOME_URL, JiraNocReqCustPortalId, JiraNocReqCustomerPortalCreateId ); } GenericData childReqSupportType = new GenericData();try { childReqSupportType.put( "value", NocSupportType.getValidCodeFor( supportType ) ); childrenRequestFieldValues.put( SUPPORT_TYPE, childReqSupportType ); } catch (UnsupportedOperationException nst) {throw new JiraNOCSupportTypeException( NocSupportType.getValidTypes(), JIRA_HOME_URL, JiraNocReqCustPortalId, JiraNocReqCustomerPortalCreateId ); } rootNodeResult.put( RequestFieldValues, childrenRequestFieldValues );return jiraClient.executeBasicPost( ResponseIssueCreationDto.class, apiCallIssueCreateByRequestType, rootNodeResult, true );}
This is what you actually need :
@Overridepublic List<ResponseItemAttachmentDto> addAttachmentToIssue(InputStream inputStream, FormDataContentDisposition fileDetail, FormDataBodyPart body, @NonNull String issueKey) { String urlParamCall = MessageFormat.format( jiraAddAttachmentToIssueKey, issueKey ); GenericData rootNodeResult = new GenericData(); rootNodeResult.put( ATTACHMENT, new AttachmentInfoHolderDto( inputStream, fileDetail, body ) ); GenericData headers = new GenericData(); headers.put( "X-Atlassian-Token", "no-check" );return jiraClient.executePostExpectingList( ResponseItemAttachmentDto.class, urlParamCall, headers, rootNodeResult, true );}
It looks like you're new here. Sign in or register to get started.