I've been a Java developer for many years developing mostly MVC Web applications using Spring. I am learning Kotlin and Android as a self development project, and mostly love it. I normally just figure things out, but I think I am missing something big here (as I like writing code that is easy to maintain and not prone to Exceptions). I understand the inter-operability with Java, I'm just confused on how my Kotlin code compiles and gives me no sort of warning whatsoever that a Java method call throws an Exception.
Here is a very simple example I have from the Android Tutorials on how to write a file that demonstrates this issue (From Camera Intent Tutorial). File.createTempFile() throws IO Exception in Java but Kotlin allows me to just call this method as if nothing throws any exceptions at all. If I remove the #Throws annotation on the method I get no warning that I'm calling a method that has the potential to throw an Exception.
#Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
}
I'm just confused on how I am supposed to keep track of Java methods that throw Exceptions. I know a lot of Exceptions and this example has the Exception in it, but by no means do I know (or could I know) every Exception possible for every method call in Java and/or Java libraries. Am I supposed to go look at the source code of every method I call to make sure I am not missing an Exception? That seems very tedious and quite a bit of overhead on a large scale codebase.
This is called perfectly fine from my code without the #Throws annotation even though it throws IO Exception in Java. How am I supposed to know if a Java method is throwing an Exception I need to take into account while coding (without looking at the source code)?
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
}
I have read the documents on Exceptions and on Java inter-operability, I am just wondering if there is an easier way to tell if a Java method throws an Exception then looking at the source code (maybe I missed something)?
https://kotlinlang.org/docs/reference/java-interop.html
https://kotlinlang.org/docs/reference/exceptions.html
//Checked Exceptions
//In Kotlin, all exceptions are unchecked, meaning that the compiler does not force you to catch any
//of
// them. So, when you call a Java method that declares a checked exception, Kotlin does not force you
//to
//do anything:
fun render(list: List<*>, to: Appendable) {
for (item in list) {
to.append(item.toString()) // Java would require us to catch IOException here
}
}
I suggest you check with Intellij. If I use a method throwing an exception in my code, It hints me. It also suggests me to include throws Exception my method definition
Consider there are 3 methods,
A()throws Exception;
B(); //which calls A inside
C();// which calls B inside
This code will compile in Java without complaining. But it's not the best practice, throw Exception is much important like return type in the method definition. Especially in multi-developer projects. It improves usability and documentation.
Am I supposed to go look at the source code of every method I call to make sure I am not missing an Exception?
While using external libs, you don't need to know about the source code but you must refer the documentation to know about its behaviours.
what's the purpose of the method.
Whether it throws Exception or not. If so, Should I handle it or not.
The return type, which you obviously know.
I am working in a repository maintained by 200 developers. And we also practice the above.
And in addition, Java reflection has the library Method.getExceptionTypes() which will list you all the exceptions throwing by a method in runtime.
Note: I am Java developer and don't know much about Kotlin grammars
Since Kotlin doesn't support checked exceptions, you're out of luck when using a Java library. You just have to be diligent about looking at the docs of methods you're calling.
If you're writing a Kotlin library, you can box your result in a class that wraps a successful result or an error. Or you can use sealed classes. For example:
sealed class QueryResult
class Success(val result: List<String>): QueryResult()
class IncorrectSyntaxError(val msg: String): QueryResult()
class ConnectionError(val msg: String): QueryResult()
And then your function can return one of the above subclasses. The receiver can then use a when statement to handle the result:
var result: List<String>? = null
val query = doQuery()
when (query ) {
is Success -> result = query.result
is IncorrectSyntaxError -> showErrorMessage(query.msg)
is ConnectionError -> showErrorMessage(query.msg)
}
Related
I have this project that I'm doing and for whatever reason, whenever I execute the program and put in the given arguments required for it (that I set and all) and occasionally an IOException is thrown before anything else is executed. It seems to be true because I got loggers everywhere and none of them are being fired. However, it seems that just the loggers are not being fired cause when I look in the json file I output to, it shows that it did do the first step of the execution, just no loggers. I'm new to log4j2 so it may be that but I'm not sure (with the loggers not being fired) but it seems weird that an IOException occurs when it shouldn't at all. Cause when I execute it again right after the crash, it runs just fine.
(Side note: this is in kotlin/jvm, but this is pertaining to the use of the JDK File class)
The exception is thrown here: https://github.com/AlexCouch/projauto/blob/master/src/main/java/thinkingcouch/projauto/Save.kt#L114
I'm on MacOSX High Sierra using Intellij IDEA 2017.3.
So what ended up happening was I had this function here for isolating a certain part of the given path to be appended to a new path and also saved to json for later use
fun Path.splitPathWithContext(context: String): File{
val presplit = this.normalize()
logger.info("presplit: $presplit")
logger.info("context: $context")
if(presplit.toString() == context){
logger.info("Path and context are the same.")
return presplit.toFile()
}
val reg = Pattern.compile("\\b$context\\b")
val ret = presplit.toString().split(reg)[1]
logger.info("ret: $ret")
return File(ret)
}
The solution was to do a strict pattern check against the context variable so that it doesn't cut at a word that contains that string but isn't that string exactly, and it needed to be exact. This solved my issue. No more problems, and no more broken paths, and I also fixed my loggers. I don't know exactly what was causing it to not do any logging, but I fixed it by setting the root level to "all" and then removing all my other logger elements since that's all I needed to do.
Currently, this is how I check if a file is playable through the JavaFX MediaPlayer, since it's the way it is done internally.
import static com.sun.media.jfxmedia.MediaManager.canPlayContentType;
import static com.sun.media.jfxmediaimpl.MediaUtils.filenameToContentType;
public boolean isPlayable(String filename) {
return canPlayContentType(filenameToContentType(filename));
}
the problem is that the packages that contain these Methods "are not API" and not accessible on Java 9 anymore. I know that there are workarounds, but I wonder if there is an actually correct, future-proof way of doing this?
I want this method to populate a Library with all the playable content within a directory:
Files.find(folderPath, Integer.MAX_VALUE, (path, attr) ->
attr.isRegularFile() && isPlayable(path.toFile().getName()))
.forEach(path -> addSong(path));
I went through the documentation of javafx.media module for the sake of finding any such built-in API and was unable to find one.
A look at the existing Implementation of filenameToContentType(String filename), which is somewhat:-
if (extension.equals(FILE_TYPE_AIF) || extension.equals(FILE_TYPE_AIFF)) {
contentType = CONTENT_TYPE_AIFF;
} else if ... other content types
That eventually checks if the current file extension is one of the supported container type and returns the content types based on the same.
The other piece on the board crucially was canPlayContentType(String contentType) which seems to be relying eventually on the supportedContentTypes for each platform as defined in the NativeMediaManager class.
Though I haven't tested the solution as proposed below primarily due to unawareness of the overview of the task that you intend to perform eventually. Yet, the closest to your current implementation and what Basic PlayBack guidelines suggests as well, was to try
Construct a Media instance out of the filename that you were providing.
Check for a MediaException if any while performing (1).
Further, the exception type MediaException.Type MEDIA_UNSUPPORTED states that
Indicates that this media type is not supported by this platform.
Drawing from the analogy with this and your current solution, you could probably make use of the this:
private static boolean isPlayable(String filename) {
try {
Media media = new Media(filename);
} catch (MediaException e) {
if (e.getType() == MediaException.Type.MEDIA_UNSUPPORTED) {
return false;
}
}
return true;
}
PS: Though I believe this could be further optimized if you actually start making use of the Media constructed(as in the above stub) right away in your piece of code instead of just dropping it.
I need to show on my panel the working dir.
I use String value = System.getProperty("user.dir"). Afterwards i put this string on label but I receive this message on console:
The method getProperty(String, String) in the type System is not applicable for the arguments (String).
I use eclipse.
Issue
I am guessing you have not gone through GWT 101 - You cannot blindly use JAVA CODE on client side.
Explanation
You can find the list of classes and methods supported for GWT from JAVA.
https://developers.google.com/web-toolkit/doc/latest/RefJreEmulation
For System only the following are supported.
err, out,
System(),
arraycopy(Object, int, Object, int, int),
currentTimeMillis(),
gc(),
identityHashCode(Object),
setErr(PrintStream),
setOut(PrintStream)
Solution
In your case Execute System.getProperty("user.dir") in your server side code and access it using RPC or any other server side gwt communication technique.
System.getProperty("key") is not supported,
but System.getProperty("key", "default") IS supported, though it will only return the default value as there is not system properties per se.
If you need the working directory during gwt compile, you need to use a custom linker or generator, grab the system property at build time, and emit it as a public resource file.
For linkers, you have to export an external file that gwt can download and get the compile-time data you want. For generators, you just inject the string you want into compiled source.
Here's a slideshow on linkers that is actually very interesting.
http://dl.google.com/googleio/2010/gwt-gwt-linkers.pdf
If you don't want to use a linker and an extra http request, you can use a generator as well, which is likely much easier (and faster):
interface BuildData {
String workingDirectory();
}
BuildData data = GWT.create(BuildData.class);
data.workingDirectory();
Then, you need to make a generator:
public class BuildDataGenerator extends IncrementalGenerator {
#Override
public RebindResult generateIncrementally(TreeLogger logger,
GeneratorContext context, String typeName){
//generator boilerplate
PrintWriter printWriter = context.tryCreate(logger, "com.foo", "BuildDataImpl");
if (printWriter == null){
logger.log(Type.TRACE, "Already generated");
return new RebindResult(RebindMode.USE_PARTIAL_CACHED,"com.foo.BuildDataImpl");
}
SourceFileComposerFactory composer =
new SourceFileComposerFactory("com.foo", "BuildDataImpl");
//must implement interface we are generating to avoid class cast exception
composer.addImplementedInterface("com.foo.BuildData");
SourceWriter sw = composer.createSourceWriter(printWriter);
//write the generated class; the class definition is done for you
sw.println("public String workingDirectory(){");
sw.println("return \""+System.getProperty("user.dir")+"\";");
sw.println("}");
return new RebindResult(RebindMode.USE_ALL_NEW_WITH_NO_CACHING
,"com.foo.BuildDataImpl");
}
}
Finally, you need to tell gwt to use your generator on your interface:
<generate-with class="dev.com.foo.BuildDataGenerator">
<when-type-assignable class="com.foo.BuildData" />
</generate-with>
Edit 2 After recieving a response from Mathworks support I've answered the question myself. In brief, there is an options class MWComponentOptions that is passed to the exported class when instantiated. This can, among other things, specify unique print streams for error output and regular output (i.e. from disp()-liked functions). Thanks for all the responses none the less :)
====================================================================
Just a quick question - is there any way to prevent MATLAB code from outputting to the Java console with disp (and similar) functions once compiled? What is useful debugging information in MATLAB quickly becomes annoying extra text in the Java logs.
The compilation tool I'm using is MATLAB Compiler (which I think is not the same as MATLAB Builder JA, but I might be wrong). I can't find any good documentation on the mcc command so am not sure if there are any options for this.
Of course if this is impossible and a direct consequence of the compiler converting all MATLAB code to its Java equivalent then that's completely understandable.
Thanks in advance
Edit This will also be useful to handle error reporting on the Java side alone - currently all MATLAB errors are sent to the console regardless of whether they are caught or not.
The isdeployed function returns true if run in a deployed application (with e.g. MATLAB Compiler or Builder JA) and false when running in live MATLAB.
You can surround your disp statements with an if isdeployed block.
I heard back from a request to Mathworks support, and they provided the following solution:
When creating whatever class has been exported, you can specify an MWComponentOptions object. This is poorly documented in R2012b, but for what I wanted the following example would work:
MWComponentOptions options = new MWComponentOptions();
PrintStream o = new PrintStream(new File("MATLAB log.log"));
options.setPrintStream(o); // send all standard dips() output to a log file
// the following ignores all error output (this will be caught by Java exception handling anyway)
options.setErrorStream((java.io.PrintStream)null);
// instantiate and use the exported class
myClass obj = new myClass(options);
obj.myMatlabFunction();
// etc...
Update
In case anyone does want to suppress all output, casing null to java.io.PrintStream ended up causing a NullPointerException in deployment. A better way to suppress all output is use to create a dummy print stream, something like:
PrintStream dummy = new PrintStream(new OutputStream() {
public void close() {}
public void flush() {}
public void write(byte[] b) {}
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
} );
Then use
options.setErrorStream(dummy);
Hope this helps :)
Another possible hack if you have a stand-alone application and don't want to bother with classes at all:
Use evalc and deploy your func name during compile:
function my_wrap()
evalc('my_orig_func(''input_var'')');
end
And compile like
mcc -m my_wrap my_orig_func <...>
Well, it is obviously yet another hack.
I am coding in GWT 2.3 using Eclipse. While I have had coding experience, it has been limited to client-side. My current project involves creating a mapping program, which takes a list of points from an Excel sheet and places them on a predefined image. Now, I have my servlet and my client code connected, and I already have some idea how to read the Excel file.
My current problem: I get the following error when I load my application on Firefox using Development Mode:
Something other than an int was returned from JSNI method '#com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::readInt()': JS value of type undefined, expected int
Development Mode's console doesn't give me any errors when I run, those it does tell me there is a [WARN] with two things I'm not using (images which I misnamed, but do not load ever).
Currently, my code is as follows:
In my Floor.java client side code:
MyServiceAsync service = (MyServiceAsync) GWT.create(MyService.class);
AsyncCallback<String> callback = new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
printerModel.setText("FAILED");
String details = caught.getMessage();
printerModel.setText(details);
}
#Override
public void onSuccess(String result) {
//I purposefully have this as an empty method so I could figure out the error
}
};
service.readFile("PrinterList.xls", callback);
In my MyService.java:
>public String readFile(String s);
In `MyServiceImpl.java`:
>public String readFile(String s) {
// TODO Auto-generated method stub
try {
} catch (Exception e) {
}
return "foo";
}
My AsyncCallback type is String, which seems to be causing the error. The method my client code calls returns a single String at this point, "fubar" (for simplicity). I thought that Strings were automatically serializable, but I am not sure. So, how do I get this error to go away? And how do I make the server code serialized?
What the exception says is basically this:
Client was trying to read an object from the data stream. Based on the signature of called method (or some other hint) the stream reader was expecting an int but found undefined instead.
As for the serializability of String, your assumption is correct. They are serializable without any effort on your part.
Without looking at the code and/or exception trace, it's difficult to say anything more.
EDIT:
Your code seems fine to me. Is there a chance that you are mixing GWT versions? That is you compiled your GWT application with 2.3, but the server classpath contains an older GWT jar (or vice versa). Take a look at:
Project GWT version settings. Project-> Properties -> Google -> Web Toolkit. Which version of GWT is selected there?
Compare the GWT settings with Project -> Properties -> Java Build Path -> Libraries. How many GWT related jars do you see there? Which version? Are there more than one gwt-servlet-x.y.jar?