Malformed PDF print doesn't catch RuntimeException - java

I try to print a PDF file and it works fine until I try to print a malformed PDF file.
I don't know why the application crashes even though I used try / catch to prevent crashes. I checked and found out that PrintManager.java:1101 throws RuntimeException:
case MSG_ON_KILL: {
if (DEBUG) {
Log.i(LOG_TAG, "onKill()");
}
String reason = (String) message.obj;
throw new RuntimeException(reason);
}
so code below shouldn't lead to crash:
public static void startPdfPrintProcedure(#NonNull Context context, #NonNull String filePath, #Nullable String jobName) {
try {
PrintManager printManager = (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
String jobName = formatDefaultJobName(context.getResources(), jobName);
PrintDocumentAdapter pda = new SimplePrintDocumentAdapter(new File(filePath));
if (printManager != null) {
try {
printManager.print(jobName, pda, null); // <- crash here even though there is a try/catch
} catch (RuntimeException e) {
showUnknownError();
}
} else {
showUnknownError();
}
} catch (RuntimeException e) {
showUnknownError();
}
}
Exception that I get after try to print PDF. :
java.lang.RuntimeException: Cannot print a malformed PDF file
at android.print.PrintManager$PrintDocumentAdapterDelegate$MyHandler.handleMessage(PrintManager.java:1101)
at android.os.Handler.dispatchMessage(Handler.java:112)
at android.os.Looper.loop(Looper.java:216)
at android.app.ActivityThread.main(ActivityThread.java:7625)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
Why try/catch code doesn't catch this exception? How can I secure this piece of code from crashing?

This happens because some "Genius" Google developer has come up with the "Great" idea of throwing an exception in the main thread causing your application to close.
I have tried to solve the problem using reflection but the implementation is too closed.
Unfortunately, you have to use it assuming the imminent closure of your application in case of incorrect files, unless you want to implement a library to check the PDF format before calling the API.
Google never fails, you always have to mess around with its implementation.
The secondary thread ends up calling this handler.
private final class MyHandler extends Handler {
public static final int MSG_ON_KILL = 5;
...
#Override
public void handleMessage(Message message) {
switch (message.what) {
...
case MSG_ON_KILL: {
if (DEBUG) {
Log.i(LOG_TAG, "onKill()");
}
String reason = (String) message.obj;
throw new RuntimeException(reason);<---------
}
default: {
throw new IllegalArgumentException("Unknown message: "
+ message.what);
}
}
}
}

One way is to check if PDF file is corrupted or not by using PDF viewer library : https://github.com/voghDev/PdfViewPager
import library : implementation 'es.voghdev.pdfviewpager:library:1.1.2'
Use below code to check if PDF file is corrupted
BasePDFPagerAdapter adapter;
PDFViewPager pdfViewPager;
pdfViewPager = findViewById(R.id.pdfViewPager);
adapter = new PDFPagerAdapter(this, path, new PdfErrorHandler() {
#Override
public void onPdfError(Throwable t) {
Log.d("pdfcorrupt",">> yes");
isPDFCorrupted = true;
}
});
pdfViewPager.setAdapter(adapter);
When PDF file is not valid, onPdfError() method will be called.
If your file is corrupted, simply do not allow to print.

Related

FirebaseVisionImage: variable 'image' might not have been initialized

I'm trying to use the example for Google Firebase (machine learning kit) in Android Studio. I'm getting an error when passing the image variable into the detector.processImage method (error shown below).
How can I get past this error? I have to use the FirebaseVisionImage.fromFilePath within a try-catch block, but the error message is telling me that the image variable may not be initialized.
error: variable image might not have been initialized
FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(MainMenuActivity.this,
Uri.fromFile(new File("/sdcard/Download/test.jpg")));
} catch (IOException e) {
e.printStackTrace();
}
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
Task<FirebaseVisionText> result = detector.processImage(image)
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
#Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
// Task completed successfully
mainText.setText("Hello!");
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Task failed with an exception
}
}
);
That error emerges because of this piece of code
FirebaseVisionImage image;
try {
image = FirebaseVisionImage.fromFilePath(
MainMenuActivity.this,
Uri.fromFile(new File("/sdcard/Download/test.jpg"))
);
} catch (IOException e) {
e.printStackTrace();
}
Now, ask yourself, what happens to image if an Exception is thrown inside the try block?
The variable might have been assigned a valid value, or it might have not.
Because you're letting the execution flow to continue (you aren't throwing the Exception to the upper level), the compiler cannot know that for sure, since the exception is thrown at run-time.
And because in Java a local variable must be initialized before usage (even with = null), the compiler is telling you to do so.
error: variable image might not have been initialized
The solution might be to initialize it with null
FirebaseVisionImage image = null;
Or, a better one, to let escape the Exception. That will signal there is a bug.
You'll also be able to completely unwrap your code from the try - catch block.
All code that needs the image should be inside the try block:
try {
FirebaseVisionImage image = FirebaseVisionImage.fromFilePath(MainMenuActivity.this,
Uri.fromFile(new File("/sdcard/Download/test.jpg")));
Task<FirebaseVisionText> result = detector.processImage(image)
.addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
#Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
// Task completed successfully
mainText.setText("Hello!");
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Task failed with an exception
}
}
);
} catch (IOException e) {
e.printStackTrace();
}
FirebaseVisionTextRecognizer detector = FirebaseVision.getInstance().getOnDeviceTextRecognizer();
Note that a catch statement that just prints the runtime exception like yours does, should usually be as high as possible in the callstack. So I'd recommend moving it to the code that alls this code, or even higher up. And keep in mind: if you don't catch that error at all, Android will print it too. So consider what you're trying to accomplish with this catch and implement it accordingly.

Typecasting with a class that is protected

I am trying to override some class of vertx web project, since I have to change some of the features. So the tricky part comes here.
#Override
public void reroute(HttpMethod method, String path) {
int split = path.indexOf('?');
if (split == -1) {
split = path.indexOf('#');
}
if (split != -1) {
log.warn("Non path segment is not considered: " + path.substring(split));
// reroute is path based so we trim out the non url path parts
path = path.substring(0, split);
}
/*((HttpServerRequestWrapper) request).setMethod(method);
((HttpServerRequestWrapper) request).setPath(path);*/
((HttpServerRequestWrapper) request).setMethod(method);
((HttpServerRequestWrapper) request).setPath(path);
request.params().clear();
// we need to reset the normalized path
normalisedPath = null;
// we also need to reset any previous status
statusCode = -1;
// we need to reset any response headers
response().headers().clear();
// special header case cookies are parsed and cached
if (cookies != null) {
cookies.clear();
}
// reset the end handlers
if (headersEndHandlers != null) {
headersEndHandlers.clear();
}
if (bodyEndHandlers != null) {
bodyEndHandlers.clear();
}
failure = null;
restart();
}
This code throws me a compilation error saying:
'HttpServerRequestWrapper cannot be accessed from outside package'
I know for a fact that we can use reflection to create objects of a class that cannot be accessed. Can reflection be used in this case? How can I fix such an issue.
Any help will be much appreciated.
In java 8 and/or without modules it is possible to just place class like that in same package as original one to get access to all package-default classes.
Otherwise you need to use reflections like in other response, but I would add that it is good idea to cache that Class and Method instance, as using Class.forName and clazz.getDeclaredMethod each time will slowdown code.
What about getting the Class object and then calling the methods on your specific (uncasted) object?
I assume request is a class attribute of type HttpServerRequestWrapper. Then, this is what I suggest:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
...
private final Method setMethod;
private final Method setPath;
public MyConstructor() {
Method tmp1 = null, tmp2 = null;
try {
final Class<?> clazz = Class.forName("io.vertx.ext.web.impl.HttpServerRequestWrapper");
tmp1 = clazz.getMethod("setMethod", HttpMethod.class);
tmp1.setAccessible(true);
tmp2 = clazz.getMethod("setPath", String.class);
tmp2.setAccessible(true);
} catch (ClassNotFoundException e) {
// do something
} catch (NoSuchMethodException e) {
// do something
} catch (SecurityException e) {
// do something
}
this.setMethod = tmp1;
this.setPath = tmp2;
}
...
#Override
public void reroute(HttpMethod method, String path) {
...
try {
this.setMethod.invoke(request, method);
this.setPath.invoke(request, path);
} catch (IllegalAccessException e) {
// do something
} catch (IllegalArgumentException e) {
// do something
} catch (InvocationTargetException e) {
// do something
}
...
}
EDIT: I updated this answer based on #GotoFinal's suggestion.
It looks like HttpServerRequestWrapper implements HttpServerRequest. So, you can change "HttpServerRequestWrapper" to "HttpServerRequest" in your code. But remember that by doing so, you'll only be able to call methods specified in the interface.
You can see those methods in https://vertx.io/docs/apidocs/io/vertx/rxjava/core/http/HttpServerRequest.html.

Android URLEncoder.encode unhandled exception java.io.UnsupportedEncodingException

I try to implement Android searchable and I want to filter query, I follow this link, this, and others. but in Android Studio I got this message unhandled exception java.io.UnsupportedEncodingException, this is my code
import java.net.URLEncoder;`
private void doSearch(String queryStr) {
// get a Cursor, prepare the ListAdapter
// and set it
//Log.e("Query",queryStr);
searchRestaurants(URLEncoder.encode(queryStr, "UTF-8"));}
You need to wrap your URLEncoder.encode()-method in a try-catch block:
try {
URLEncoder.encode(queryStr, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e("Yourapp", "UnsupportedEncodingException");
}
The reason you're getting this error is that some platforms might not support UTF-8 encoding. Android definitely does, so you'll never receive this Exception, but you still need to handle it to make the compiler happy.
However, your code won't do anything, you'll need to store the result of the encode()-operation in a variable, e.g. String myEncodedQuery = URLEncoder.encode(queryStr, "UTF-8");.
import java.net.URLEncoder;
private void doSearch(String queryStr) {
// get a Cursor, prepare the ListAdapter
// and set it
//Log.e("Query",queryStr);
try {
final String encodedPath = URLEncoder.encode(queryStr, "UTF-8"));
searchRestaurants(encodedPath);
} catch (UnsupportedEncodingException ec) {
Log.d(TAG, ec.printStacktrace);
}
}

Vaadin Upload component how get fileName before submitUpload?

I try make implementation for comparing the files before they are uploaded.
If file whith name is exist in system ask about create new version or just override it.
Here is the problem, how to get file name?
I can't use receiveUpload(), because after this method file is remove from upload component ?
The problem is that once you start an upload using the Upload component, it can only be interrupted by calling the interruptUpload() method, and you cannot resume anytime later.
The interruption is permanent.
This means you cannot pause in the middle of the upload to see if you already have the file in your system. You have to upload the file all the way.
Considering this drawback, you can sill check in your system if you have the file, after the upload finishes. If you have the file, you can show a confirmation dialog in which you decide wether to keep the file or overwrite.
The following is an example in which I check in the "system" (I just keep a String list with the filenames) if the file has already been uploaded:
public class RestrictingUpload extends Upload implements Upload.SucceededListener, Upload.Receiver {
private List<String> uploadedFilenames;
private ByteArrayOutputStream latestUploadedOutputStream;
public RestrictingUpload() {
setCaption("Upload");
setButtonCaption("Upload file");
addSucceededListener(this);
setReceiver(this);
uploadedFilenames = new ArrayList<String>();
}
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
latestUploadedOutputStream = new ByteArrayOutputStream();
return latestUploadedOutputStream;
}
#Override
public void uploadSucceeded(SucceededEvent event) {
if (fileExistsInSystem(event.getFilename())) {
confirmOverwrite(event.getFilename());
} else {
uploadedFilenames.add(event.getFilename());
}
}
private void confirmOverwrite(final String filename) {
ConfirmDialog confirmDialog = new ConfirmDialog();
String message = String.format("The file %s already exists in the system. Overwrite?", filename);
confirmDialog.show(getUI(), "Overwrite?", message, "Overwrite", "Cancel", new ConfirmDialog.Listener() {
#Override
public void onClose(ConfirmDialog dialog) {
if (dialog.isConfirmed()) {
copyFileToSystem(filename);
}
}
});
}
private void copyFileToSystem(String filename) {
try {
IOUtils.write(latestUploadedOutputStream.toByteArray(), new FileOutputStream(filename));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
}
private boolean fileExistsInSystem(String filename) {
return uploadedFilenames.contains(filename);
}
}
Note that I have used 2 external libraries:
Apache Commons IO 2.4 (http://mvnrepository.com/artifact/commons-io/commons-io/2.4) for writing to streams
ConfirmDialog from Vaadin Directory (https://vaadin.com/directory#addon/confirmdialog)
You can get the code snippet for this class from Gist: https://gist.github.com/gabrielruiu/9960772 which you can paste into your UI and test it out.

How do I write a unit test to cover the case where an IOException is thrown?

I have the following class:
public class FileLoader {
private Map<Brand, String> termsOfUseText = new HashMap<Brand, String>();
public void load() {
for (Brand brand : Brand.values()) {
readAndStoreTermsOfUseForBrand(brand);
}
}
private void readAndStoreTermsOfUseForBrand(Brand brand) {
String resourceName = "termsOfUse/" + brand.name().toLowerCase() + ".txt";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceName);
try {
String content = IOUtils.toString(in);
termsOfUseText.put(brand, content);
} catch (IOException e) {
throw new IllegalStateException(String.format("Failed to find terms of use source file %s", resourceName),e);
}
}
public String getTextForBrand(Brand brand) {
return termsOfUseText.get(brand);
}
}
Brand is an enum, and I need all the valid .txt files to be on the classpath. How do I make the IOException occur, given that the Brand enum contains all the valid brands and therfore all the .txt files for them exist?
Suggestions around refactoring the current code are welcome if it makes it more testable!
Three options I see right off:
Use PowerMock to mock IOUtils.toString(). I consider PowerMock to be quite a last resort. I'd rather refactor the source to something a little more test-friendly.
Extract the IOUtils call to a protected method. Create a test-specific subclass of your class that overrides this method and throws the IOException.
Extract the InputStream creation to a protected method. Create a test-specific subclass to override the method and return a mock InputStream.
I would suggest a bit of refactoring. All your methods are void, this usually means they are not functional.
For example, you can extract this functionality:
private String readTermsOfUseForBrand(InputStream termsOfUserIs) {
try {
String content = IOUtils.toString(in);
return content;
} catch (IOException e) {
throw new IllegalStateException(String.format("Failed to find terms of use source file %s", resourceName), e);
}
return null;
}
So that we can assert on the String result in our tests.
Of course this is not functional code, as it reads from an Input Stream. And it does so with IOUtils.toString() method that cannot be mocked easily (well, there's PowerMock but as Ryan Stewart said it's the last resort).
To test IO exceptions you can create a failing input stream (tested with JDK7):
public class FailingInputStream extends InputStream {
#Override
public int read() throws IOException {
throw new IOException("Test generated exception");
}
}
And test like that:
#Test
public void testReadTermsOfUseForBrand() {
FileLoader instance = new FileLoader();
String result = instance.readTermsOfUseForBrand(new FailingInputStream());
assertNull(result);
}
Missing file will cause NullPointerException because getResourceAsStream will return null and you will have in==null. IOException in this case may actually be pretty rare. If it's critical for you to see it, I can only think of instrumenting this code to throw it if code is executed in test scope. But is it really that important?
I would use a mock to accomplish this.
Example (untested, just to give you some thought):
#Test(expected=IllegalStateException.class)
public void testThrowIOException() {
PowerMockito.mockStatic(IOUtils.class);
PowerMockito.when(IOUtils.toString()).thenThrow(
new IOException("fake IOException"));
FileLoader fileLoader = new FileLoader();
Whitebox.invokeMethod(fileLoader,
"readAndStoreTermsOfUseForBrand", new Brand(...));
// If IllegalStateException is not thrown then this test case fails (see "expected" above)
}
Code below is completely untested
To cause the IOException use:
FileInputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceName);
in.mark(0);
//read some data
in.reset(); //IOException
To test the IOException case use:
void test
{
boolean success = false;
try
{
//code to force ioException
}
catch(IOException ioex)
{
success = true;
}
assertTrue(success);
}
In JUnit4
#Test(expected=IOException.class)
void test
{
//code to force ioException
}
Other JUnit
void test
{
try
{
//code to force IOException
fail("If this gets hit IO did not occur, fail test");
}
catch(IOException ioex)
{
//success!
}
}

Categories

Resources