Serialize ANTLR Exceptions for GWT RPC - java

I am using GWT-RPC to call an ANTLR grammar.
If the grammar fails, I create an object containing the errors/exceptions that were thrown by the grammar and return it to the client.
When I do this I get the exception:
com.google.gwt.user.client.rpc.SerializationException: Type 'org.antlr.runtime.NoViableAltException' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded.
I have found that there is an identical class with the addition of a public no argument constructor (needed for GWT-RPC serialization) in the com.google.appengine.repackaged.org.antlr.runtime package.
How do I convert the org.antlr.runtime.NoViableAltException into a com.google.appengine.repackaged.org.antlr.runtime.NoViableAltException?

Do you need the exceptions themselves? I'd think not - you probably need the message or at most the stack trace. Since you're repackaging the exceptions anyway, just repack the needed strings and send those over the wire.

As an alternative for creating new Exceptions that can be serialized, I have made my Parser override the emitErrorMessage method from BaseRecognizer.
#members {
#Override
public void emitErrorMessage(String msg) {
// The original prints to stdout.
// You can do what you like with the message.
}
}
As Tassos suggested in his answer, I did not actually need the exception, just the message from it.

Related

Kotlin/Java nullability setting

Given this Java interface in okhttp3.ws.WebSocketListener:
public interface WebSocketListener {
(...)
void onFailure(IOException e, Response response);
(...)
}
Kotlin assumes a signature like this:
override fun onFailure(e: IOException, response: Response) {
e.printStackTrace()
(...)
}
If I now start my app in Airplane mode, it attempts to connect to the web socket. The web socket can't connect and returns a 'null' response to 'onFailure()' - which is correct at this point. But Kotlin checks that the response is null and crashes my app even before it can print the exception stack trace.
So: How do I force Kotlin to assume '#Nullable' for anything that is not annotated?
The setting should be project-wide, not system-wide.
Several searches on Google gave no usable results. So I wonder whether I am the first one to encounter this issue and whether Kotlin is ready for use already.
Do I really need to convert the class back to Java?
When dealing with a java type having no nullability information, you
can work with it as either a nullable or a nonnull type. meaning in your case you can simply change the type of response to Response?.
override fun onFailure(e: IOException, response: Response?) {
e.printStackTrace()
(...)
}
From Kotlin in Action
sometimes Java
code contains information about nullability,
expressed using annotations. When this
information is present in the code, Kotlin
uses it. Thus #Nullable String in Java is
seen as String? by Kotlin, and #NotNull String is just String. The interesting question is what happens when the annotations aren’t
present. In that case, the Java type becomes a platform type in
Kotlin.
PLATFORM TYPES
A platform type is essentially a type for which
Kotlin doesn’t have nullability information; you can work with it as
either a nullable or a nonnull type. This means, just
as in Java, you have full responsibility for the operations you
perform with that type.

Should exceptions be used to describe user input errors?

I have a service that saves a tree-like structure to a database. Before persisting the tree, the tree gets validated, and during validation, a number of things can go wrong. The tree can have duplicate nodes, or a node can be missing an important field (such as its abbreviation, full name, or level).
In order to communicate to the service what went wrong, I'm using exceptions. When the validateTree() method encounters a problem, it throws the appropriate exception. The HttpService class then uses this exception to form the appropriate response (e.g. in response to an AJAX call).
public class HttpService {
private Service service;
private Logger logger;
// ...
public HttpServiceResponse saveTree(Node root) {
try {
service.saveTree(root);
} catch (DuplicateNodeException e) {
return HttpServiceResponse.failure(DUPLICATE_NODE);
} catch (MissingAbbreviationException e) {
return HttpServiceResponse.failure(MISSING_ABBREV);
} catch (MissingNameException e) {
return HttpServiceResponse.failure(MISSING_NAME);
} catch (MissingLevelException e) {
return HttpServiceResponse.failure(MISSING_LEVEL);
} catch (Exception e) {
logger.log(e.getMessage(), e. Logger.ERROR);
return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
}
}
}
public class Service {
private TreeDao dao;
public void saveTree(Node root)
throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {
validateTree(root);
dao.saveTree(root);
}
private void validateTree(Node root)
throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {
// validate and throw checked exceptions if needed
}
}
I want to know, is this a good use of exceptions? Essentially, I'm using them to convey error messages. An alternative would be for my saveTree() method to return an integer, and that integer would convey the error. But in order to do this, I would have to document what each return value means. That seems to be more in the style of C/C++ than Java. Is my current use of exceptions a good practice in Java? If not, what's the best alternative?
No, exceptions aren't a good fit for the validation you need to do here. You will likely want to display multiple validation error messages, so that the user can see all the validation errors at once, and throwing a separate exception for each invalid input won't allow that.
Instead create a list and put errors in it. Then you can show the user the list of all the validation errors.
Waiting until your request has gotten all the way to the DAO seems like the wrong time to do this validation. A server-side front controller should be doing validation on these items before they get passed along any farther, as protection against attacks such as injection or cross-site scripting.
TL;DR The Java-side parts you showed us are nearly perfect. But you could add an independent validation check and use that from the client side before trying to save.
There are many software layers involved, so let's have a look at each of them - there's no "one size fits all" answer here.
For the Service object, it's the perfect solution to have it throw exceptions from the saveTree() method if it wasn't able to save the tree (for whatever reason, not limited to validation). That's what exceptions are meant for: to communicate that some method couldn't do its job. And the Service object shouldn't rely on some external validation, but make sure itself that only valid data are saved.
The HttpService.saveTree() should also communicate to its caller if it couldn't save the tree (typically indicated by an exception from the Service). But as it's an HTTP service, it can't throw exceptions, but has to return a result code plus a text message, just the way you do it. This can never contain the full information from the Java exception, so it's a good decision that you log any unclear errors here (but you should make sure that the stack trace gets logged too!), before you pass an error result to the HTTP client.
The web client UI software should of course present detailed error lists to the user and not just a translated single exception. So, I'd create an HttpService.validateTree(...) method that returns a list of validation errors and call that from the client before trying to save. This gives you the additional possibility to check for validity independent of saving.
Why do it this way?
You never have control what happens in the client, inside some browser, you don't even know whether the request is coming from your app or from something like curl. So you can't rely on any validation that your JavaScript (?) application might implement. All of your service methods should reject invalid data, by doing the validation themselves.
Implementing the validation checks in a JavaScript client application still needs the same validation inside the Java service (see above), so you'd have to maintain two pieces of code in different languages doing exactly the same business logic - don't repeat yourself! Only if the additional roundtrip isn't tolerable, then I'd regard this an acceptable solution.
Visible and highly noticeable, both in terms of the message itself and how it indicates which dialogue element users must repair.
From Guru Nielsen,
https://www.nngroup.com/articles/error-message-guidelines/

Why doesn't slf4j's Logger has a method that accepts both varargs for the message and an exception?

SLF4J's Logger have logging methods that either accept exception or varargs but not both.
Any idea why?
The problem with the missing signature is that sometimes I'd like to both log an exception and provide params to the message, but I don't have a method signature to do both.
Referring to In the presence of an exception/throwable, is it possible to parameterize a logging statement?, you can do that since SLF4J 1.6.0, if the exception is the last argument :
Yes, as of SLF4J 1.6.0, but not in previous versions. The SLF4J
API supports parametrization in the presence of an exception,
assuming the exception is the last parameter. Thus,
String s = "Hello world";
try {
Integer i = Integer.valueOf(s);
} catch (NumberFormatException e) {
logger.error("Failed to format {}", s, e);
}
will print the NumberFormatException with its stack trace as expected.
The java compiler will invoke the error method taking a String and two
Object arguments. SLF4J, in accordance with the programmer's most
probable intention, will interpret NumberFormatException instance as a
throwable instead of an unused Object parameter. In SLF4J versions
prior to 1.6.0, the NumberFormatException instance was simply ignored.
If the exception is not the last argument, it will be treated as a
plain object and its stack trace will NOT be printed. However, such
situations should not occur in practice.
As an example implementation , this is the method that gets called by Logback (this method is in the class ch.qos.logback.classic.spi.EventArgUtil and gets called by ch.qos.logback.classic.spi.LoggingEvent ) :
public static final Throwable extractThrowable(Object[] argArray) {
if (argArray == null || argArray.length == 0) {
return null;
}
final Object lastEntry = argArray[argArray.length - 1];
if (lastEntry instanceof Throwable) {
return (Throwable) lastEntry;
}
return null;
}
Possible reason is that varargs has to be the last arg in the signature and it was complicated to add a Object parameter (which is intended for exception) followed by Object... parameter. As per answer by #Berger it appears that it was resolved in version SLF4J 1.6.0. However, I resolved the same problem differently. I wrote an Open Source library MgntUtils (available from Maven Central repository and github). One of the utilities there is extracting stacktrace from Throwable as a String. Also optionaly this utility can filter out some irrelevant parts of stacktrace and leave it very concised and easy to read format. So in this case you can pass extracted stacktrace to your logger as part of varargs. I found it very convinient aspeccially with filtered stacktrace. It would look like this:
LOGGER.error("My message {} {}", MyStringParam, TextUtils.getStacktrace(e));
Here is the link to the article that explains where to get the library and how to use it: MgntUtils Open source library Library comes with source code and javadoc

Returning error codes from a method

I'd like to ask something confuses me a lot. Here is the scenario, lets say I have a method preparePayload that takes some argument like messageType, destAddr etc. The duty of method is construct a fully payload (with headers, prefixes etc). Here is the problem, I want to return statusCode (which is enum, like STATUS_OK,STATUS_INVALID_DEST, STATUS_INVALID_MSG_TYPE etc.), and than respect to return status I'd like to implement my logic. But if there is no error (STATUS_OK), I need the prepared payload to move on. So my method should return eighter payload or status code.
In C language, simply sending payload buffer address as an argument to preparePayload method solves the problem perfectly. When the method returns, simply reading payload from the buffer address and moving on the application works. How can I implement this kind of logic in Java?
In addition, preparePayload method is just an example I gave, so the methods I implemented may return String, int[], some class object that I wrote etc. I mean, the type of object that method should return in success case may vary.
Any suggestion will very welcome.
Besides changing to exceptions, there is one more hackish way to allow for "input/output" parameters, like:
public ResultEnum preparePayLoad(List<PayLoad> toPrepare, ... other args) {
...
PayLoad newThing = ...
...
toPrepare.add(newThing);
return someEnum;
}
So, you could use such an approach to "emulate" the "C style"; but the more Java/OO would be
public PayLoad preparePayLoad(args) {
...
PayLoad newThing = ...
...
return newThing;
}
and to throw (checked or unchecked) exceptions for error situations.
The correct idiom in Java is to throw a checked exception (some will say unchecked is better, there is a slight controversy here).
The three important mechanisms you get is:
automatic propagation of error codes up the stack. If you do not handle some type of error in your code (don't check for it), it will get propagated up as an exception - you don't need layered checks (and avoid an error of returning an invalid result, quite common in C),
exceptions work as an "alternate return type", ensuring type safety for both correct results and the error messages (which are full objects - and can contain any number of useful information besides the code)
checked exceptions allow the compiler to check if all the important error statuses are handled in some way.
You can create a class, a wrapper, for example:
public class Result {
public enum Status {
STATUS_OK, STATUS_INVALID_DEST, STATUS_INVALID_MSG_TYPE
}
Status status;
String payload;
}
that will be returned by your method preparePayload. Then, when you call your method, you can do it like this:
Result result = preparePayload(args);
//better will be a switch with case for each possible status
if (result.state == Result.State.STATUS_OK)
//do what you want with payload
System.out.println(result.payload);
else
return;

Adding Metadata to Java RMI

I'm trying to create a system that will, on every RMI call,
1) gather some data about the current local system state (let's say the system time)
2) serialize it and transparently add it to the data sent over the wire with the call (ie, without changing the signature of the stub method being called)
3) deserialize it on the other side and take some action (let's say logging it to a file)
4) do the same thing in reverse when the method returns
I've was trying at first to do this with AspectJ, adding a pointcut at java.rmi.server.RemoteRef's invoke method that would allow me to add the metadata to the params Object array, but I've now discovered that AspectJ can't advise already-compiled code, which makes a lot of sense.
So, what's the right way to do this?
Well, I am not sure if I am getting enough context from what you are saying, but I think you could write the metadata upon serialization/deserialization of objects passed to and received from the server.
For instance, let's say you server is returning Jedi instances. And Jedi is a Serializable class. Then you could use the writeObject() and readObject() methods (as explained in the Java Serialization Specification) to write whatever special additional information that you may need at the client/server side.
For instance:
public class Jedi {
....
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.writeObject(new Date());
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
Date sysDate = (Date) stream.readObject();
System.out.println(sysDate);
stream.defaultReadObject();
}
}
The only problem as that you would be forced to do this for every serializable object you interchange with your server.
You could also investigate RMI/JERI in the Jini 2 project. JERI stands for Java Extensible Remote Invocation protocol, i.e. you can customize it in numerous ways.

Categories

Resources