fineuploader file list empty - java
I am using fineuploader within a struts system but am having trouble getting the file list in the server code.
My jsp contains the following code:
$("#fine-uploader").fineUploader({
debug: true,
request: {
endpoint: '/NRGI/act_MultiPhotoUpload.do'
},
deleteFile: {
enabled: true,
endpoint: '/uploads'
},
retry: {
enableAuto: true
}
});
with the following div near the bottom of the page:
<div id="fine-uploader"></div>
The action actMultiPhotoUpload points to a class via the struts.config.xml file:
<action path="/act_MultiPhotoUpload" name="FileUploadForm" scope="request" validate="true"
type="com.solarcentury.nrgi.document.action.MultiUploadAction"
input="/D5_PhotoLibrary.jsp">
</action>
The class MultiUploadAction is taken from your UploadReceiver and is as follows:
public class MultiUploadAction extends Action {
static Static_Env_Object seo = new Static_Env_Object();
private String UPLOAD_NOT_ALLOWED = "exe";
private EnvUtils eu;
// JUST FOR TESTING
private static final File UPLOAD_DIR = new File("Test/uploads");
private static File TEMP_DIR = new File("Test/uploadsTemp");
private static String CONTENT_LENGTH = "Content-Length";
private static int SUCCESS_RESPONSE_CODE = 200;
#Override
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
HttpSession session = request.getSession();
String sId = session.getId();
eu = new EnvUtils(seo.get_Env_Name(), this.getClass().getSimpleName());
/* **************************************** */
/* * The code for the session timeout check */
/* **************************************** */
if (session.getAttribute("SESS_User") == null) {
eu.log("NO SESSION", "Session timed out...");
return (mapping.findForward("globaltimeout"));
}
UserObject suo = new UserObj_Util(session).get_SessUser();
WebAlertMessages wam = new WebAlertMessages(request, suo.get_Language_ID());
DemonUtil du = new DemonUtil(seo.get_Env_Name());
// DateUtils dateUtil = new DateUtils();
RequestParser requestParser = null;
boolean isIframe = request.getHeader("X-Requested-With") == null || !request.getHeader("X-Requested-With").equals("XMLHttpRequest");
try
{
// resp.setContentType(isIframe ? "text/html" : "text/plain");
response.setContentType("text/plain");
response.setStatus(SUCCESS_RESPONSE_CODE);
// resp.addHeader("Access-Control-Allow-Origin", "http://192.168.130.118:8080");
// resp.addHeader("Access-Control-Allow-Credentials", "true");
// resp.addHeader("Access-Control-Allow-Origin", "*");
if (ServletFileUpload.isMultipartContent(request))
{
MultipartUploadParser multipartUploadParser = new MultipartUploadParser(request, TEMP_DIR, request.getSession().getServletContext());
requestParser = RequestParser.getInstance(request, multipartUploadParser);
writeFileForMultipartRequest(requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
else
{
requestParser = RequestParser.getInstance(request, null);
//handle POST delete file request
if (requestParser.getMethod() != null
&& requestParser.getMethod().equalsIgnoreCase("DELETE"))
{
String uuid = requestParser.getUuid();
handleDeleteFileRequest(uuid, response);
}
else
{
writeFileForNonMultipartRequest(request, requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
}
} catch (Exception e)
{
eu.log("UploadReceiver","Problem handling upload request" + e);
if (e instanceof MultiUploadAction.MergePartsException)
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, true, requestParser);
}
else
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, false, requestParser);
}
}
return (new ActionForward(mapping.getInput()));
}
And I use the MultipartUploadParser, RequestParser from the server java examples on the website.
When I step through the code, how ever many files I select to upload, the file list is always empty. Obviously I am doing something stupid here, but would appreciate any guidance please.
I have seen a similar support question where the asker was having trouble getting the filelist, also using struts, but there wasn't an answer against the question
Added on 14/11/2013
The full code is as follows:
The full listing of MultiUploadAction.java is as follows:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.solarcentury.nrgi.document.action;
/**
*
* #author Roy
*/
import DemonWeb.DmForms.FileUploadForm;
import DemonWeb.DmLogic.DemonUtil;
import DemonWeb.DmLogic.Project;
import DemonWeb.DmSession.Static_Env_Object;
import DemonWeb.DmSession.UserObj_Util;
import DemonWeb.DmSession.UserObject;
import DemonWeb.DmSession.WebAlertMessages;
import DemonWeb.Utils.EnvUtils;
import com.solarcentury.nrgi.document.bean.Document;
import com.solarcentury.nrgi.document.logic.DocumentController;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.Enumeration;
import java.util.Collections;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
/**
*
* #author ajantham
*/
public class MultiUploadAction extends Action {
static Static_Env_Object seo = new Static_Env_Object();
private String UPLOAD_NOT_ALLOWED = "exe";
private EnvUtils eu;
// JUST FOR TESTING
private static final File UPLOAD_DIR = new File("uploads");
private static File TEMP_DIR = new File("uploadsTemp");
private static String CONTENT_LENGTH = "Content-Length";
private static int SUCCESS_RESPONSE_CODE = 200;
#Override
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
HttpSession session = request.getSession();
String sId = session.getId();
eu = new EnvUtils(seo.get_Env_Name(), this.getClass().getSimpleName());
/* **************************************** */
/* * The code for the session timeout check */
/* **************************************** */
if (session.getAttribute("SESS_User") == null) {
eu.log("NO SESSION", "Session timed out...");
return (mapping.findForward("globaltimeout"));
}
UserObject suo = new UserObj_Util(session).get_SessUser();
WebAlertMessages wam = new WebAlertMessages(request, suo.get_Language_ID());
DemonUtil du = new DemonUtil(seo.get_Env_Name());
// DateUtils dateUtil = new DateUtils();
RequestParser requestParser = null;
boolean isIframe = request.getHeader("X-Requested-With") == null || !request.getHeader("X-Requested-With").equals("XMLHttpRequest");
try
{
// resp.setContentType(isIframe ? "text/html" : "text/plain");
response.setContentType("text/plain");
response.setStatus(SUCCESS_RESPONSE_CODE);
// resp.addHeader("Access-Control-Allow-Origin", "http://192.168.130.118:8080");
// resp.addHeader("Access-Control-Allow-Credentials", "true");
// resp.addHeader("Access-Control-Allow-Origin", "*");
if (ServletFileUpload.isMultipartContent(request))
{
MultipartUploadParser multipartUploadParser = new MultipartUploadParser(request, TEMP_DIR, request.getSession().getServletContext());
requestParser = RequestParser.getInstance(request, multipartUploadParser);
writeFileForMultipartRequest(requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
else
{
requestParser = RequestParser.getInstance(request, null);
//handle POST delete file request
if (requestParser.getMethod() != null
&& requestParser.getMethod().equalsIgnoreCase("DELETE"))
{
String uuid = requestParser.getUuid();
handleDeleteFileRequest(uuid, response);
}
else
{
writeFileForNonMultipartRequest(request, requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
}
} catch (Exception e)
{
eu.log("UploadReceiver","Problem handling upload request" + e);
if (e instanceof MultiUploadAction.MergePartsException)
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, true, requestParser);
}
else
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, false, requestParser);
}
}
return (new ActionForward(mapping.getInput()));
}
public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
String uuid = req.getPathInfo().replaceAll("/", "");
handleDeleteFileRequest(uuid, resp);
}
private void handleDeleteFileRequest(String uuid, HttpServletResponse resp) throws IOException
{
FileUtils.deleteDirectory(new File(UPLOAD_DIR, uuid));
if (new File(UPLOAD_DIR, uuid).exists())
{
eu.log("UploadReceiver","couldn't find or delete " + uuid);
}
else
{
eu.log("UploadReceiver","deleted " + uuid);
}
resp.setStatus(SUCCESS_RESPONSE_CODE);
// resp.addHeader("Access-Control-Allow-Origin", "*");
}
private void writeFileForNonMultipartRequest(HttpServletRequest req, RequestParser requestParser) throws Exception
{
File dir = new File(UPLOAD_DIR, requestParser.getUuid());
dir.mkdirs();
String contentLengthHeader = req.getHeader(CONTENT_LENGTH);
long expectedFileSize = Long.parseLong(contentLengthHeader);
if (requestParser.getPartIndex() >= 0)
{
writeFile(req.getInputStream(), new File(dir, requestParser.getUuid() + "_" + String.format("%05d", requestParser.getPartIndex())), null);
if (requestParser.getTotalParts()-1 == requestParser.getPartIndex())
{
File[] parts = getPartitionFiles(dir, requestParser.getUuid());
File outputFile = new File(dir, requestParser.getFilename());
for (File part : parts)
{
mergeFiles(outputFile, part);
}
assertCombinedFileIsVaid(requestParser.getTotalFileSize(), outputFile, requestParser.getUuid());
deletePartitionFiles(dir, requestParser.getUuid());
}
}
else
{
writeFile(req.getInputStream(), new File(dir, requestParser.getFilename()), expectedFileSize);
}
}
private void writeFileForMultipartRequest(RequestParser requestParser) throws Exception
{
File dir = new File(UPLOAD_DIR, requestParser.getUuid());
dir.mkdirs();
if (requestParser.getPartIndex() >= 0)
{
writeFile(requestParser.getUploadItem().getInputStream(), new File(dir, requestParser.getUuid() + "_" + String.format("%05d", requestParser.getPartIndex())), null);
if (requestParser.getTotalParts()-1 == requestParser.getPartIndex())
{
File[] parts = getPartitionFiles(dir, requestParser.getUuid());
File outputFile = new File(dir, requestParser.getOriginalFilename());
for (File part : parts)
{
mergeFiles(outputFile, part);
}
assertCombinedFileIsVaid(requestParser.getTotalFileSize(), outputFile, requestParser.getUuid());
deletePartitionFiles(dir, requestParser.getUuid());
}
}
else
{
writeFile(requestParser.getUploadItem().getInputStream(), new File(dir, requestParser.getFilename()), null);
}
}
private void assertCombinedFileIsVaid(int totalFileSize, File outputFile, String uuid) throws MultiUploadAction.MergePartsException
{
if (totalFileSize != outputFile.length())
{
deletePartitionFiles(UPLOAD_DIR, uuid);
outputFile.delete();
throw new MultiUploadAction.MergePartsException("Incorrect combined file size!");
}
}
private static class PartitionFilesFilter implements FilenameFilter
{
private String filename;
PartitionFilesFilter(String filename)
{
this.filename = filename;
}
#Override
public boolean accept(File file, String s)
{
return s.matches(Pattern.quote(filename) + "_\\d+");
}
}
private static File[] getPartitionFiles(File directory, String filename)
{
File[] files = directory.listFiles(new MultiUploadAction.PartitionFilesFilter(filename));
Arrays.sort(files);
return files;
}
private static void deletePartitionFiles(File directory, String filename)
{
File[] partFiles = getPartitionFiles(directory, filename);
for (File partFile : partFiles)
{
partFile.delete();
}
}
private File mergeFiles(File outputFile, File partFile) throws IOException
{
FileOutputStream fos = new FileOutputStream(outputFile, true);
try
{
FileInputStream fis = new FileInputStream(partFile);
try
{
IOUtils.copy(fis, fos);
}
finally
{
IOUtils.closeQuietly(fis);
}
}
finally
{
IOUtils.closeQuietly(fos);
}
return outputFile;
}
private File writeFile(InputStream in, File out, Long expectedFileSize) throws IOException
{
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(out);
IOUtils.copy(in, fos);
if (expectedFileSize != null)
{
Long bytesWrittenToDisk = out.length();
if (!expectedFileSize.equals(bytesWrittenToDisk))
{
eu.log("UploadReceiver","Expected file {} to be {} bytes; file on disk is {} bytes " + new Object[] { out.getAbsolutePath(), expectedFileSize, 1 });
out.delete();
throw new IOException(String.format("Unexpected file size mismatch. Actual bytes %s. Expected bytes %s.", bytesWrittenToDisk, expectedFileSize));
}
}
return out;
}
catch (Exception e)
{
throw new IOException(e);
}
finally
{
IOUtils.closeQuietly(fos);
}
}
private void writeResponse(PrintWriter writer, String failureReason, boolean isIframe, boolean restartChunking, RequestParser requestParser)
{
if (failureReason == null)
{
// if (isIframe)
// {
// writer.print("{\"success\": true, \"uuid\": \"" + requestParser.getUuid() + "\"}<script src=\"http://192.168.130.118:8080/client/js/iframe.xss.response.js\"></script>");
// }
// else
// {
writer.print("{\"success\": true}");
// }
}
else
{
if (restartChunking)
{
writer.print("{\"error\": \"" + failureReason + "\", \"reset\": true}");
}
else
{
// if (isIframe)
// {
// writer.print("{\"error\": \"" + failureReason + "\", \"uuid\": \"" + requestParser.getUuid() + "\"}<script src=\"http://192.168.130.118:8080/client/js/iframe.xss.response.js\"></script>");
// }
// else
// {
writer.print("{\"error\": \"" + failureReason + "\"}");
// }
}
}
}
private class MergePartsException extends Exception
{
MergePartsException(String message)
{
super(message);
}
}
}
The full source of MultipartUploadParser.java is as follows:
package com.solarcentury.nrgi.document.action;
import DemonWeb.DmSession.Static_Env_Object;
import DemonWeb.Utils.EnvUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileCleaningTracker;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
public class MultipartUploadParser
{
// final Logger log = LoggerFactory.getLogger(MultipartUploadParser.class);
static Static_Env_Object seo = new Static_Env_Object();
private EnvUtils eu;
private Map<String, String> params = new HashMap<String, String>();
private List<FileItem> files = new ArrayList<FileItem>();
// fileItemsFactory is a field (even though it's scoped to the constructor) to prevent the
// org.apache.commons.fileupload.servlet.FileCleanerCleanup thread from attempting to delete the
// temp file before while it is still being used.
//
// FileCleanerCleanup uses a java.lang.ref.ReferenceQueue to delete the temp file when the FileItemsFactory marker object is GCed
private DiskFileItemFactory fileItemsFactory;
public MultipartUploadParser(HttpServletRequest request, File repository, ServletContext context) throws Exception
{
this.eu = new EnvUtils(seo.get_Env_Name(), "MultipartUploadParser " + "1.0.0.0");
if (!repository.exists() && !repository.mkdirs())
{
throw new IOException("Unable to mkdirs to " + repository.getAbsolutePath());
}
fileItemsFactory = setupFileItemFactory(repository, context);
ServletFileUpload upload = new ServletFileUpload(fileItemsFactory);
List<FileItem> formFileItems = upload.parseRequest(request);
parseFormFields(formFileItems);
if (files.isEmpty())
{
eu.log("MultipartUploadParser","No files were found when processing the request. Debugging info follows");
writeDebugInfo(request);
throw new FileUploadException("No files were found when processing the request.");
}
else
{
writeDebugInfo(request);
}
}
private DiskFileItemFactory setupFileItemFactory(File repository, ServletContext context)
{
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
factory.setRepository(repository);
FileCleaningTracker pTracker = FileCleanerCleanup.getFileCleaningTracker(context);
factory.setFileCleaningTracker(pTracker);
return factory;
}
private void writeDebugInfo(HttpServletRequest request)
{
eu.log("MultipartUploadParser","-- POST HEADERS --");
for (String header : Collections.list((Enumeration<String>) request.getHeaderNames()))
{
eu.log("MultipartUploadParser", header + "header " + request.getHeader(header));
}
eu.log("MultipartUploadParser","-- POST PARAMS --");
for (String key : params.keySet())
{
eu.log("MultipartUploadParser", key + " key " + params.get(key));
}
}
private void parseFormFields(List<FileItem> items) throws UnsupportedEncodingException
{
for (FileItem item : items)
{
if (item.isFormField())
{
String key = item.getFieldName();
String value = item.getString("UTF-8");
if (StringUtils.isNotBlank(key))
{
params.put(key, StringUtils.defaultString(value));
}
}
else
{
files.add(item);
}
}
}
public Map<String, String> getParams()
{
return params;
}
public List<FileItem> getFiles()
{
if (files.isEmpty())
{
throw new RuntimeException("No FileItems exist.");
}
return files;
}
public FileItem getFirstFile()
{
if (files.isEmpty())
{
throw new RuntimeException("No FileItems exist.");
}
return files.iterator().next();
}
}
MultiUploadAction decides that the request isMultipartContent and so calls MultipartUploadParser. This class successfully
checks the directory structure and then uses its method ParseFormFields to buld up a list of files.
However it does not find any files or form fields, and so on line 62 of MultipartUploadParser files.isEmpty() is true,
and so an exception is thrown (line 70)
It doesn't matter how many files I select in the client, the file list is always empty.
Many thanks for your help in this - much appreciated
I know this is very old, but I ran into this same problem. In my implementation I had tried to adapt the example endpoint code into my Spring MVC project. I discovered that the Spring MVC framework was actually calling the same Apache ServletFileUpload.parseRequest BEFORE passing the request to my controller and detecting the multipart, fetching the params, etc. The framework was parsing the multipart request despite whether I was using MutlipartHttpServlet request, or simply HttpServletRequest as my signature for the controller method. When my code in the MultipartUploadParser hit ServletFileUpload.parseRequest again, this time it returned an empty List because they had already been parsed.
The endpoint example code in the git repo for Fine Uploader works as it is, it was just my adaptation with Spring MVC that didn't work.
Related
Java. Server don't send proper HTML
I wrote little app in Java but it don't serv HTML properly. Problem occurs when method checkCookies return false. Normally an "else" clause should be executed but this doesn't happen. Some intresting thing - the app is going 3 times from start of handle() method to first condition (counter is increasing). I don't know how to repair it. If i got a cookie with name "Login" or i manually modify method to always return true it's working good. Main file: Loginpage.java import com.sun.net.httpserver.HttpServer; import java.net.InetSocketAddress; public class Loginpage { public static void main (String[] args) throws Exception{ HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/form", new Form()); server.setExecutor(null); server.start(); } } Form.java import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import java.io.*; import java.net.HttpCookie; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; public class Form implements HttpHandler { int counter = 0; #Override public void handle(HttpExchange httpExchange) throws IOException { counter++; System.out.println(counter); List<String> cookies = httpExchange.getRequestHeaders().get("Cookie"); HttpCookie cookie; String response = "<html><body>system</body></html>"; String method = httpExchange.getRequestMethod(); if (checkCookies(cookies)) { response = "<html><body> Hello! </body></html>"; } else { if (method.equals("GET")) { response = "<html><body><form method='post'>" + "<input type='text' name='username'><br>" + "<input type='password' name='pass'><br>" + "<input type='submit' value='login'<br>" + "</form></body></html>"; } else if (method.equals("POST")) { InputStreamReader isr = new InputStreamReader(httpExchange.getRequestBody(), "utf-8"); BufferedReader br = new BufferedReader(isr); String formData = br.readLine(); Map data = parseFormData(formData); if (checkData(data)) { cookie = new HttpCookie("Login", String.valueOf(counter + (counter * 12))); httpExchange.getResponseHeaders().add("Set-Cookie", cookie.toString()); } } } httpExchange.sendResponseHeaders(200, response.length()); OutputStream os = httpExchange.getResponseBody(); os.write(response.getBytes()); os.close(); } private boolean checkCookies(List<String> cookies) { boolean isValid = false; for (String s : cookies) { System.out.println(s); if (s.matches("Login.*")) { isValid = true; } } System.out.println(isValid); return isValid; } private boolean checkData(Map<String, String> data) { DAO dao = new DAO(); String username = data.get("username"); System.out.println(username); String password = data.get("pass"); System.out.println(password); if (dao.checkData(username, password)) { return true; } else return false; } private static Map<String, String> parseFormData(String formData) throws UnsupportedEncodingException { Map<String, String> map = new HashMap<>(); String[] pairs = formData.split("&"); for (String pair : pairs) { String[] keyValue = pair.split("="); String value = new URLDecoder().decode(keyValue[1], "UTF-8"); map.put(keyValue[0], value); } return map; } } UPDATE I found the cause of my problem. If I send a empty List to the checkCookies() method the program "hangs". Adding the condition if (cookies == null) return false; in checkCookies() method solved the problem but I do not know why it was not just return false before fix. Can anyone explain it?
Java DecriptionInfo on Word DocX
I'm pulling my hair out as I cannot get the samples to work - hopefully someone can help.. I would like to DETECT if a docx and a doc file is password protected/encrypted. I have seen this posted in a few places but I cannot get it work - it doesnt throw an exception. Can someone see what I am doing wrong. Note I only need to detect the password..i dont want to open the document. String fileLocation = "C:/myfile.docx"; File file = new File(fileLocation); FileInputStream fis = new FileInputStream(file.getAbsolutePath()); POIFSFileSystem pfis = new POIFSFileSystem(fis); try{ EncryptionInfo info = new EncryptionInfo(pfis); EncryptionMode mode = info.getEncryptionMode(); Decryptor d = Decryptor.getInstance(info); //Try and open it if(!d.verifyPassword(Decryptor.DEFAULT_PASSWORD)) { //file is encrypted } } catch(GeneralSecurityException gse) { //file is encrypted } catch(EncryptedDocumentException edc) { //file is encrypted }
I haven't elaborated much to get the code smaller, but I've simply taken one of the factory classes - like SlideShowFactory - and modified it for H/XWPF. As H/XWPF hasn't got a common interface on the document level (as of now), the quick&dirty approach is to return an Object. import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import org.apache.poi.EncryptedDocumentException; import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.poifs.crypt.Decryptor; import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.OfficeXmlFileException; import org.apache.poi.util.IOUtils; import org.apache.poi.xwpf.usermodel.XWPFDocument; public class EncDetect { public static void main(String[] args) { String dir = "/home/kiwiwings/project/poi/poi/test-data"; String[] files = { "document/bug53475-password-is-solrcell.docx", "document/password_tika_binaryrc4.doc", "document/58067.docx", "document/58804.doc" }; for (String f : files) { try { DocumentFactory.create(new File(dir, f)); System.out.println(f + " not encrypted"); } catch (EncryptedDocumentException e) { System.out.println(f + " is encrypted"); } catch (Exception e) { System.out.println(f + " " +e.getMessage()); } } } static class DocumentFactory { public static Object create(NPOIFSFileSystem fs) throws IOException { return create(fs, null); } public static Object create(final NPOIFSFileSystem fs, String password) throws IOException { DirectoryNode root = fs.getRoot(); // Encrypted OOXML files go inside OLE2 containers, is this one? if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) { InputStream stream = null; try { stream = DocumentFactoryHelper.getDecryptedStream(fs, password); return createXWPFDocument(stream); } finally { IOUtils.closeQuietly(stream); } } // If we get here, it isn't an encrypted XWPF file // So, treat it as a regular HWPF one boolean passwordSet = false; if (password != null) { Biff8EncryptionKey.setCurrentUserPassword(password); passwordSet = true; } try { return createHWPFDocument(fs); } finally { if (passwordSet) { Biff8EncryptionKey.setCurrentUserPassword(null); } } } public static Object create(InputStream inp) throws IOException, EncryptedDocumentException { return create(inp, null); } public static Object create(InputStream inp, String password) throws IOException, EncryptedDocumentException { // If clearly doesn't do mark/reset, wrap up if (! inp.markSupported()) { inp = new PushbackInputStream(inp, 8); } // Ensure that there is at least some data there byte[] header8 = IOUtils.peekFirst8Bytes(inp); // Try to create if (NPOIFSFileSystem.hasPOIFSHeader(header8)) { NPOIFSFileSystem fs = new NPOIFSFileSystem(inp); return create(fs, password); } if (DocumentFactoryHelper.hasOOXMLHeader(inp)) { return createXWPFDocument(inp); } throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); } public static Object create(File file) throws IOException, EncryptedDocumentException { return create(file, null); } public static Object create(File file, String password) throws IOException, EncryptedDocumentException { return create(file, password, false); } public static Object create(File file, String password, boolean readOnly) throws IOException, EncryptedDocumentException { if (!file.exists()) { throw new FileNotFoundException(file.toString()); } NPOIFSFileSystem fs = null; try { fs = new NPOIFSFileSystem(file, readOnly); return create(fs, password); } catch(OfficeXmlFileException e) { IOUtils.closeQuietly(fs); return createXWPFDocument(file, readOnly); } catch(RuntimeException e) { IOUtils.closeQuietly(fs); throw e; } } protected static Object createHWPFDocument(NPOIFSFileSystem fs) throws IOException, EncryptedDocumentException { return new HWPFDocument(fs.getRoot()); } protected static Object createXWPFDocument(InputStream stream) throws IOException, EncryptedDocumentException { return new XWPFDocument(stream); } protected static Object createXWPFDocument(File file, boolean readOnly) throws IOException, EncryptedDocumentException { try { OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE); return new XWPFDocument(pkg); } catch (InvalidFormatException e) { throw new IOException(e); } } } }
Java - Clipboard modification : Works in Eclipse, but not as JAR
I created a software based on two sources (stated in the code below) which detect HTML copied to the clipboard and change local images to base 64 ones. This code works perfectly when I run it in Eclipse, but not using a JAR. Initially, I was not using the method getHtmlDataFlavor, but I added it when I tried the software as a JAR. Then, I had to ensure in HtmlSelection.getTransferData to have if (flavor.getRepresentationClass() == java.io.Reader.class) otherwise it would crash. But using the JAR, I'm only getting the plain text version! Though, it stills works when ran in Eclipse. Does someone have an idea ? I am running on Windows 10. Executing in command line using : java -jar ClipboardImageToBase64-1.0.0-jar-with-dependencies.jar GitHub project : https://github.com/djon2003/ClipboardImageToBase64 /** * Library from HTML parsing : https://jsoup.org * * Code based on : * - http://stackoverflow.com/a/14226456/214898 * - http://elliotth.blogspot.ca/2005/01/copying-html-to-clipboard-from-java.html */ import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class ClipBoardListener extends Thread implements ClipboardOwner { Clipboard sysClip = Toolkit.getDefaultToolkit().getSystemClipboard(); private static DataFlavor HTML_FLAVOR = new DataFlavor("text/html;class=java.io.Reader", "HTML"); private int nbImagesConverted = 0; private Transferable currentTransferable; #Override public void run() { Transferable trans = sysClip.getContents(this); TakeOwnership(trans); } #Override public void lostOwnership(Clipboard c, Transferable t) { System.out.println("Copy to clipboard detected"); try { ClipBoardListener.sleep(250); // waiting e.g for loading huge // elements like word's etc. } catch (Exception e) { System.out.println("Exception: " + e); } Transferable contents = sysClip.getContents(this); try { process_clipboard(contents, c); } catch (Exception ex) { Logger.getLogger(ClipBoardListener.class.getName()).log(Level.SEVERE, null, ex); } TakeOwnership(currentTransferable); } void TakeOwnership(Transferable t) { sysClip.setContents(t, this); } private void getHtmlDataFlavor(Transferable t) { DataFlavor df = null; for (DataFlavor tDf : t.getTransferDataFlavors()) { if (tDf.getMimeType().contains("text/html")) { if (tDf.getRepresentationClass() == java.io.Reader.class) { df = tDf; break; } } } HTML_FLAVOR = df; } public void process_clipboard(Transferable t, Clipboard c) { String tempText = ""; Transferable trans = t; currentTransferable = t; getHtmlDataFlavor(t); if (HTML_FLAVOR == null) { System.out.println("No HTML flavor detected"); return; } nbImagesConverted = 0; try { if (trans != null ? trans.isDataFlavorSupported(HTML_FLAVOR) : false) { if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) { tempText = (String) trans.getTransferData(DataFlavor.stringFlavor); } java.io.Reader r = (java.io.Reader) trans.getTransferData(HTML_FLAVOR); StringBuilder content = getReaderContent(r); String newHtml = changeImages(content); currentTransferable = new HtmlSelection(newHtml, tempText); System.out.println("Converted " + nbImagesConverted + " images"); } else { System.out.println("Not converted:" + trans.isDataFlavorSupported(HTML_FLAVOR)); System.out.println(trans.getTransferData(HTML_FLAVOR)); /* for (DataFlavor tt : trans.getTransferDataFlavors()) { if (tt.getMimeType().contains("text/html")) { System.out.println("-------"); System.out.println(tt.toString()); } } */ } } catch (Exception e) { currentTransferable = t; System.out.println("Conversion error"); e.printStackTrace(); } } private String changeImages(StringBuilder content) throws RuntimeException, IOException { Document doc = Jsoup.parse(content.toString()); Elements imgs = doc.select("img"); for (Element img : imgs) { String filePath = img.attr("src"); filePath = filePath.replace("file:///", ""); filePath = filePath.replace("file://", ""); File file = new File(filePath); if (file.exists()) { String encoded = Base64.encodeBase64String(FileUtils.readFileToByteArray(file)); String extension = file.getName(); extension = extension.substring(extension.lastIndexOf(".") + 1); String dataURL = "data:image/" + extension + ";base64," + encoded; img.attr("src", dataURL); // or whatever nbImagesConverted++; } } String html = doc.outerHtml(); html = html.replaceAll("(?s)<!--.*?-->", ""); //Remove html comments return html; // returns the modified HTML } private StringBuilder getReaderContent(java.io.Reader r) throws IOException { char[] arr = new char[8 * 1024]; StringBuilder buffer = new StringBuilder(); int numCharsRead; while ((numCharsRead = r.read(arr, 0, arr.length)) != -1) { buffer.append(arr, 0, numCharsRead); } r.close(); return buffer; } private static class HtmlSelection implements Transferable { private String html; private String plainText; public HtmlSelection(String html, String plainText) { this.html = html; this.plainText = plainText; } public DataFlavor[] getTransferDataFlavors() { DataFlavor[] dfs = {HTML_FLAVOR, DataFlavor.stringFlavor}; return dfs; } public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.getMimeType().contains("text/html") || flavor.getMimeType().contains("text/plain"); } public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (flavor.getMimeType().contains("text/html")) { if (flavor.getRepresentationClass() == java.io.Reader.class) { return new StringReader(html); } else { return html; } } else { return plainText; } //throw new UnsupportedFlavorException(flavor); } } }
I finally fixed all my problems. I created a GitHub project for those who are interested. https://github.com/djon2003/ClipboardImageToBase64
Java : InputStream to Multi-part file conversion, result file is empty
I am working on a Java application in which I am trying to create a Multipart file out of downloaded InputStream. Unfortunately, it is not working and the Multipart file is empty. I checked the size of savedFile on disk before copying it to Multipart, and it has correct size, attributes, content. What am I doing wrong in the conversion, there is no stacktrace, as I am catching it. Code : // InputStream contains file data. byte[] bytes = IOUtils.toByteArray(inputStream); File file = new File(msg + "temp"); if (file.exists() && file.isDirectory()) { OutputStream outputStream = new FileOutputStream(new File(msg + "temp" + "/" + groupAttachments.getFileName())); outputStream.write(bytes); outputStream.close(); } java.io.File savedFile = new java.io.File(msg + "temp" + "/" + groupAttachments.getFileName()); DiskFileItem fileItem = new DiskFileItem("file", "text/plain", false, savedFile.getName(), (int) savedFile.length(), savedFile.getParentFile()); fileItem.getOutputStream(); MultipartFile multipartFile = new CommonsMultipartFile(fileItem); System.out.println("Saved file size is "+savedFile.length()); if (multipartFile.isEmpty()) { System.out.println("Dropbox uploaded multipart file is empty"); } else { System.out.println("Multipart file is not empty."); } this.dropboxTask.insertFile(multipartFile, "", savedPersonalNoteObject.getNoteid(), (long) 0, true); Path path = Paths.get(msg + "temp" + "/" + groupAttachments.getFileName()); Console output : Multipart file is not empty Bytes are not null File path is /My Group Input stream is not null Saved file size is 4765 Dropbox uploaded multipart file is empty Multipart file is empty Bytes are not null What am I doing wrong in the conversion? Any help would be nice. Thanks a lot.
The DiskFileItem uses a DeferredFileOutputStream which uses an in-memory byte-array that is only filled when bytes are actually transferred. Since files are used directly and no bytes are actually copied, the byte-array is never filled. See for yourself in the source code: Source code CommonsMultipartFile Source code DiskFileItem Source code DeferredFileOutputStream So, instead of just calling fileItem.getOutputStream();, transfer the bytes to fill the in-memory byte-array: try (OutputStream out = fileItem.getOutputStream(); InputStream in = Files.newInputStream(file.toPath())) { IOUtils.copy(in, dfos); } and then the tranferTo call will work. This appears to be a bit cumbersome for just moving a file: CommonsMultipartFile only calls fileItem.write((File)dest) in the transferTo method. Below are two test cases, one using the DiskFileItem and one using the LocalFileItem. The code for LocalFileItem is shown further below. I used dependencies org.springframework:spring-web:4.2.2.RELEASE, commons-fileupload:commons-fileupload:1.3.1 and junit:junit:4.12 Test class CommonMp: import static org.junit.Assert.*; import java.io.*; import java.nio.charset.*; import java.nio.file.*; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.springframework.web.multipart.commons.CommonsMultipartFile; public class CommonMp { private final Charset CS = StandardCharsets.UTF_8; #Test public void testLocalMp() { Path testInputFile = null, testOutputFile = null; try { testInputFile = prepareInputFile(); LocalFileItem lfi = new LocalFileItem(testInputFile); CommonsMultipartFile cmf = new CommonsMultipartFile(lfi); System.out.println("Empty: " + cmf.isEmpty()); testOutputFile = testInputFile.getParent().resolve("testMpOutput.txt"); cmf.transferTo(testOutputFile.toFile()); System.out.println("Size: " + cmf.getSize()); printOutput(testOutputFile); } catch (Exception e) { e.printStackTrace(); fail(); } finally { deleteSilent(testInputFile, testOutputFile); } } #Test public void testMp() { Path testInputFile = null, testOutputFile = null; try { testInputFile = prepareInputFile(); DiskFileItem di = new DiskFileItem("file", "text/plain", false, testInputFile.getFileName().toString(), (int) Files.size(testInputFile), testInputFile.getParent().toFile()); try (OutputStream out = di.getOutputStream(); InputStream in = Files.newInputStream(testInputFile)) { IOUtils.copy(in, out); } CommonsMultipartFile cmf = new CommonsMultipartFile(di); System.out.println("Size: " + cmf.getSize()); testOutputFile = testInputFile.getParent().resolve("testMpOutput.txt"); cmf.transferTo(testOutputFile.toFile()); printOutput(testOutputFile); } catch (Exception e) { e.printStackTrace(); fail(); } finally { deleteSilent(testInputFile, testOutputFile); } } private Path prepareInputFile() throws IOException { Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir")); Path testInputFile = tmpDir.resolve("testMpinput.txt"); try (OutputStream out = Files.newOutputStream(testInputFile)){ out.write("Just a test.".getBytes(CS)); } return testInputFile; } private void printOutput(Path p) throws IOException { byte[] outBytes = Files.readAllBytes(p); System.out.println("Output: " + new String(outBytes, CS)); } private void deleteSilent(Path... paths) { for (Path p : paths) { try { if (p != null) p.toFile().delete(); } catch (Exception ignored) {} } } } The custom LocalFileItem class, YMMV! import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemHeaders; public class LocalFileItem implements FileItem { private static final long serialVersionUID = 2467880290855097332L; private final Path localFile; public LocalFileItem(Path localFile) { this.localFile = localFile; } #Override public void write(File file) throws Exception { Files.move(localFile, file.toPath(), StandardCopyOption.REPLACE_EXISTING); } #Override public long getSize() { // Spring's CommonsMultipartFile caches the file size and uses it to determine availability. long size = -1L; try { size = Files.size(localFile); } catch (IOException ignored) {} return size; } #Override public void delete() { localFile.toFile().delete(); } /* *** properties and unsupported methods *** */ private FileItemHeaders headers; private String contentType; private String fieldName; private boolean formField; #Override public FileItemHeaders getHeaders() { return headers; } #Override public void setHeaders(FileItemHeaders headers) { this.headers = headers; } #Override public InputStream getInputStream() throws IOException { throw new IOException("Only method write(File) is supported."); } public void setContentType(String contentType) { this.contentType = contentType; } #Override public String getContentType() { return contentType; } #Override public String getName() { return localFile.getFileName().toString(); } #Override public boolean isInMemory() { return false; } #Override public byte[] get() { throw new RuntimeException("Only method write(File) is supported."); } #Override public String getString(String encoding) throws UnsupportedEncodingException { throw new RuntimeException("Only method write(File) is supported."); } #Override public String getString() { throw new RuntimeException("Only method write(File) is supported."); } #Override public String getFieldName() { return fieldName; } #Override public void setFieldName(String name) { this.fieldName = name; } #Override public boolean isFormField() { return formField; } #Override public void setFormField(boolean state) { this.formField = state; } #Override public OutputStream getOutputStream() throws IOException { throw new IOException("Only method write(File) is supported."); } }
Library for processing Annotations
I've been trying to search the internet, but it seems I cannot find a library for helping processing of Annotations in a POJO. Is there any that exist? Currently we can process this through code like this: // Get id Object id = null; for (Field field : obj.getClass().getDeclaredFields()){ String fieldName = field.getName(); Object fieldValue = field.get(obj); if (field.isAnnotationPresent(Id.class)){ id = fieldValue; } } Is there a library to help quickly process annotation and with the associated value.
Take a look at How do I read all classes from a Java package in the classpath? I was using https://code.google.com/p/reflections/, and now switched to this package com.clemble.test.reflection; import java.io.File; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.JarURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class AnnotationReflectionUtils { /** URL prefix for loading from the file system: "file:" */ public static final String FILE_URL_PREFIX = "file:"; /** URL protocol for an entry from a jar file: "jar" */ public static final String URL_PROTOCOL_JAR = "jar"; /** URL protocol for an entry from a zip file: "zip" */ public static final String URL_PROTOCOL_ZIP = "zip"; /** URL protocol for an entry from a JBoss jar file: "vfszip" */ public static final String URL_PROTOCOL_VFSZIP = "vfszip"; /** URL protocol for a JBoss VFS resource: "vfs" */ public static final String URL_PROTOCOL_VFS = "vfs"; /** URL protocol for an entry from a WebSphere jar file: "wsjar" */ public static final String URL_PROTOCOL_WSJAR = "wsjar"; /** URL protocol for an entry from an OC4J jar file: "code-source" */ public static final String URL_PROTOCOL_CODE_SOURCE = "code-source"; /** Separator between JAR URL and file path within the JAR */ public static final String JAR_URL_SEPARATOR = "!/"; // Taken from https://stackoverflow.com/questions/1456930/how-do-i-read-all-classes-from-a-java-package-in-the-classpath public static <T extends Annotation> List<Class<?>> findCandidates(String basePackage, Class<T> searchedAnnotation) { ArrayList<Class<?>> candidates = new ArrayList<Class<?>>(); Enumeration<URL> urls; String basePath = basePackage.replaceAll("\\.", File.separator); try { urls = Thread.currentThread().getContextClassLoader().getResources(basePath); } catch (IOException e) { throw new RuntimeException(e); } while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (isJarURL(url)) { try { candidates.addAll(doFindPathMatchingJarResources(url, basePath, searchedAnnotation)); } catch (IOException e) { throw new RuntimeException(e); } } else { File directory = new File(url.getFile()); if (directory.exists() && directory.isDirectory()) { for (File file : new File(url.getFile()).listFiles()) fetchCandidates(basePackage, file, searchedAnnotation, candidates); } } } return candidates; } private static <T extends Annotation> void fetchCandidates(String basePackage, File candidate, Class<T> searchedAnnotation, List<Class<?>> candidates) { if (candidate.isDirectory()) { for (File file : candidate.listFiles()) fetchCandidates(basePackage + "." + candidate.getName(), file, searchedAnnotation, candidates); } else { String fileName = candidate.getName(); if (fileName.endsWith(".class")) { String className = fileName.substring(0, fileName.length() - 6); Class<?> foundClass = checkCandidate(basePackage + "." + className, searchedAnnotation); if (foundClass != null) candidates.add(foundClass); } } } public static boolean isJarURL(URL url) { String protocol = url.getProtocol(); return (URL_PROTOCOL_JAR.equals(protocol) || URL_PROTOCOL_ZIP.equals(protocol) || URL_PROTOCOL_WSJAR.equals(protocol) || (URL_PROTOCOL_CODE_SOURCE .equals(protocol) && url.getPath().contains(JAR_URL_SEPARATOR))); } public static <T extends Annotation> Class<?> checkCandidate(String className, Class<T> searchedAnnotation) { try { Class<?> candidateClass = Class.forName(className); Target target = searchedAnnotation.getAnnotation(Target.class); for(ElementType elementType: target.value()) { switch(elementType) { case TYPE: if (candidateClass.getAnnotation(searchedAnnotation) != null) return candidateClass; break; case CONSTRUCTOR: for(Constructor<?> constructor: candidateClass.getConstructors()) if(constructor.getAnnotation(searchedAnnotation) != null) return candidateClass; break; case METHOD: for(Method method: candidateClass.getMethods()) if(method.getAnnotation(searchedAnnotation) != null) return candidateClass; break; case FIELD: for(Field field: candidateClass.getFields()) if(field.getAnnotation(searchedAnnotation) != null) return candidateClass; break; default: break; } } } catch (ClassNotFoundException e) { } catch (NoClassDefFoundError e) { } return null; } /** * Find all resources in jar files that match the given location pattern * via the Ant-style PathMatcher. * * #param rootDirResource the root directory as Resource * #param subPattern the sub pattern to match (below the root directory) * #return the Set of matching Resource instances * #throws IOException in case of I/O errors * #see java.net.JarURLConnection * #see org.springframework.util.PathMatcher */ protected static <T extends Annotation> Set<Class<?>> doFindPathMatchingJarResources(URL sourceUrl, String basePackage, Class<T> searchedAnnotation) throws IOException { URLConnection con = sourceUrl.openConnection(); JarFile jarFile; String jarFileUrl; String rootEntryPath; boolean newJarFile = false; if (con instanceof JarURLConnection) { // Should usually be the case for traditional JAR files. JarURLConnection jarCon = (JarURLConnection) con; jarFile = jarCon.getJarFile(); jarFileUrl = jarCon.getJarFileURL().toExternalForm(); JarEntry jarEntry = jarCon.getJarEntry(); rootEntryPath = (jarEntry != null ? jarEntry.getName() : ""); } else { // No JarURLConnection -> need to resort to URL file parsing. // We'll assume URLs of the format "jar:path!/entry", with the protocol // being arbitrary as long as following the entry format. // We'll also handle paths with and without leading "file:" prefix. String urlFile = sourceUrl.getFile(); int separatorIndex = urlFile.indexOf(JAR_URL_SEPARATOR); if (separatorIndex != -1) { jarFileUrl = urlFile.substring(0, separatorIndex); rootEntryPath = urlFile.substring(separatorIndex + JAR_URL_SEPARATOR.length()); jarFile = getJarFile(jarFileUrl); } else { jarFile = new JarFile(urlFile); jarFileUrl = urlFile; rootEntryPath = ""; } newJarFile = true; } try { if (!"".equals(rootEntryPath) && !rootEntryPath.endsWith("/")) { // Root entry path must end with slash to allow for proper matching. // The Sun JRE does not return a slash here, but BEA JRockit does. rootEntryPath = rootEntryPath + "/"; } Set<Class<?>> result = new LinkedHashSet<Class<?>>(8); for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) { JarEntry entry = entries.nextElement(); String entryPath = entry.getName(); if (entryPath.startsWith(rootEntryPath) && entryPath.endsWith(".class")) { int entryLength = entryPath.length(); String className = entryPath.replaceAll(File.separator, ".").substring(0, entryLength - 6); Class<?> foundClass = checkCandidate(className, searchedAnnotation); if (foundClass != null) result.add(foundClass); } } return result; } finally { // Close jar file, but only if freshly obtained - // not from JarURLConnection, which might cache the file reference. if (newJarFile) { jarFile.close(); } } } /** * Resolve the given jar file URL into a JarFile object. */ protected static JarFile getJarFile(String jarFileUrl) throws IOException { if (jarFileUrl.startsWith(FILE_URL_PREFIX)) { try { return new JarFile(new URI(jarFileUrl.replaceAll(" ", "%20")).getSchemeSpecificPart()); } catch (URISyntaxException ex) { // Fallback for URLs that are not valid URIs (should hardly ever happen). return new JarFile(jarFileUrl.substring(FILE_URL_PREFIX.length())); } } else { return new JarFile(jarFileUrl); } } } This is based on some Spring utility, class which I could not use directly in my application, but I forgot which one was it.