I'm writting a client-server application. Now I'm just doing error handling. If a error occurs at the server (after a request from the client), the server should create an error object, serialize it and send it to the client.
In the error object I have a field for the error code. Of course I could place an enum in this object listing all possible error I want to cover, but then the serialized object gets to big.
Thus, I'm thinking about writting an external enum class available for the server and the client and only sending the error code from the server to the client.
Would this be a good idea?
If the client receives such an error code how can he then look up the corresponding enum in the enum class?
Just send the error code that you defined in your enum:
public enum ErrorCode {
OK(0), KO(1);
// ...
}
public class Error implements Serializable {
private int code;
private String message;
// ...
}
public void myMethod() {
// ...
// something went bad!
InternalError ie = getMyInternalErrorSomehow();
Error error = new Error(ie.getErrorCode().getCode(),
"something bad happened and i am sending you a nice message");
client.send(error);
}
Related
I read about custom exception and as:
Thorben suggest here:
https://stackify.com/java-custom-exceptions/#wpautbox_about
Baeldung suggested here: https://www.baeldung.com/java-new-custom-exception
A custom exception should be more beneficial than the original exception, otherwise it would loose its purpose.Right?
To do that we should always pass the throwable cause to our custom exception.
I have my application specific ErrorCode enums which have a custom error code and a custom message.
#Getter
#AllArgsConstructor
public enum ErrorType {
DATABASE_SERVICE_UNAVAILABLE(9001, "Cant persist to Database"),
//and more...
private final int errorCode;
private final String errorMessage;
}
While writing a exception mapper what should I send as response?
1)Custom ErrorCode Enum (Only errorcode and error msg)
OR
2)Custom ErrorCode Enum + Throwable cause (Both)
If we not send throwable, then what would be its purpose?
While writing a exception mapper what should I send as response?
If by "response", you mean the response returned by a Controller, then I think you should send the error code and error message. Why would a client be interested in your throwable object. Just give the client an understandable reason for the error. You should just log the exception in your application for debugging purpose.
I've got two root exception types my service is throwing
class ServiceException extends RuntimeException {
private Status status;
private String someString;
// Boilerplate omitted
}
class RetryableServiceException extends ServiceException {
// This class has no new fields
}
Because there's a common retry framework our clients will use which determines whether to retry or not based on the exception class.
But the problem, obviously, is that when the client gets the response and calls Response.readEntity(Class <T> entityType) they will just get an instance of whatever class they're trying to read, since they have the same fields.
Clearly I need to add some other field which distinguishes these two objects, but how can I add that to the builders and constructors in a way that:
Doesn't require a ton of client logic,
doesn't needlessly complicate the exception objects, and
can be understood by Jackson?
To answer your main issue, You don't want to couple the clients and the server so tightly by having the clients use the same exact Exception classes used on the server, create a generic error bean and map exceptions to that bean then serialise/de-serialise it. You can do that in a transparent way using javax.ws.rs.ext.ExceptionMapper, this error bean can have canRetry or shouldRetry fields. An example implementation
public class RetryableServiceExceptionMapper implements ExceptionMapper<RetryableServiceException> {
#Context
Request request;
public Response toResponse(RetryableServiceException exception) {
ApiError error = ApiError.builder().canRetry(true).message(exception.getMessage()).build();
return Response.status(status).cacheControl(cacheControl).tag(eTag).entity(error).type(APPLICATION_XML);;
}
}
I am trying to implement the REST component in Mule Flow and I was able to expose REST services also and the response is coming back to client also. But When I put Mule Java Component to access the properties of the REST component response, I am not able to do that. Below is the code of my Mule message processor,
public class RestResponseProcessor implements Callable{
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
Object messagePayload = eventContext.getMessage().getPayload();
System.out.println("Message payload class is " + messagePayload.getClass());
org.mule.module.jersey.JerseyResourcesComponent jerseyResponse = (org.mule.module.jersey.JerseyResourcesComponent) messagePayload;
System.out.println("jerseyResponse.getClass() is " + jerseyResponse.getClass());
return eventContext;
}
}
The output for the first sysout is
Message payload class is class org.mule.module.jersey.JerseyResourcesComponent$2 but when I trying to cast it org.mule.module.jersey.JerseyResourcesComponent object, it is giving classCastException, java.lang.ClassCastException: org.mule.module.jersey.JerseyResourcesComponent$2 cannot be cast to org.mule.module.jersey.JerseyResourcesComponent
What does this $2 means after the class name and what can be the possible solution to this.
Basically I am trying to route my message based on the REST component response before sending the response to client.
Hope I am clear with my question.
I got the answer from Mule forum.
$2 is an anonymous class of type org.mule.api.transport.OutputHandler created by the Jersey component.
I tried using "Byte Array To String" and it worked. It solved my purpose.
This question already has answers here:
Should web services throw exceptions OR result objects
(7 answers)
Closed 8 years ago.
I want define service as web service.
I define a method with register name. Its a class as input parameter with RegisterParam name and a return type with RegisterResult name as output.
public class RegisterParam{
String name;
String family;
}
public class RegisterResult{
Integer registr_id;
}
public interface Service{
public RegisterResult register(RegistrParam param);
}
If register service failed and its logic not doing so I have two solution for notify to service caller:
In RegisterResult class add a property as result_code and a enumeration for its value. If its value is zero means register sercice successfully done and if its value is else of zero means register service failed and result_code shows reason of fail.
register service throws a exception when it is falied and if dont any exception throwed means register service done successfully.
My question is: what above solution is bettr and why?
I think you should differ two different scenarios:
1) An exception occurs, like some environment (e.g. database) is not available.
In this case I would throw an exception which is automatically converted into an SOAPFault by the web service implementation. The advantage on this one is, that the caller of your service get's also an exception and can handle that by it's exception handling.
2) An expected business "error" happend, like the user is not logged in or did not provide the necessary information to enable the service to complete successful.
The caller of your web service receives an response message which the caller has to interpret and maybe wants to show it to the user which provided the information.
At the end it depends on your interface contract you provide to your interface users! Most important on that one is to describe how your service handles different errors scenarios.
case 1 no result:
public interface Service{
public void register(RegistrParam param);
}
In this case your Service can send a HTTP Status Code like 200. Your client will interpret the status code this way:
200: ok i'm registered
400: hm don't know why but failed...
If you want to understand what happened and why is your request failed with 400 error, you have to check your server logs or something like that.
case 2 with result:
public interface Service{
public Response register(RegistrParam param);
}
I'm sending always a Response object to my clients:
public class Response {
private ResponseStatus status; // enum: (OK, ERROR, BAD_REQUEST)
private ResultType type; // enum: (RegisterResult, LoginResult etc...) defines how to interpret the field "data"
private Object data; // RegisterResult.java as jsonstring or Exception.java as jsonstring etc...
private long time = -1L; // execution time
}
If I'm developing my client, I can always understand why my request was failed.
Hello everyone,
I have been banging my head really hard trying to solve this problem. I really appreciate if anyone can please have a look at my problem and help me.
I have multiple clients that uses Java RMI to establish a connection (register()) and receive a list of connects clients from the server (get()). My goal is to get clients to talk to each other using RMI, without having to register themselves, only the server so far is being register.
I am trying to pass a reference of the client object to the server.
I am getting the following error:
java.rmi.MarshalException: error marshalling arguments; nested exception is:
java.io.NotSerializableException: Client
I do not want to use Serialization (I believe), as I don't want to pass the object itself, but a reference. Client1 should be able to send a message to Client2 by calling client2.messsage(String username, String message);
I believe I should just show you at this point how I have implemented my code:
public interface RMIClientIntf extends Remote {
public void message(String name, String message) throws RemoteException;
public String getName() throws RemoteException;
}
The previous code is what all clients should implement. If the message() function gets called from another client, that means the other class is sending a message.
My client class itself:
public class Client implements RMIClientIntf {
public Client() throws RemoteException { super(); }
public String getName() throws RemoteException { }
}
Now, the Main class that creates an instance of client calls the following, to send the remote object to the server:
final Client client = new Client();
server.register((RMIClientIntf) client, name);
On the server side, the register method is defined as:
public interface RMIServerIntf extends Remote {
public String register(RMIClientIntf cl, String userName) throws RemoteException;
public RMIClientIntf[] get() throws RemoteException;
}
public class Server extends UnicastRemoteObject implements RMIServerIntf {
public String register(RMIClientIntf cl, String userName) throws RemoteException {
ClientStruct newClient = new ClientStruct(cl, userName);
/* Store the ClientStruct */
return new String("SUCCESS");
}
}
After registering, each client will request the list of connected users. The function in the server is the following:
public RMIClientIntf[] get() throws RemoteException {
RMIClientIntf[] users = new RMIClientIntf[openConnections.size()];
/* Fill in users from ClientStruct */
return users;
}
If Client were to also implement Serializable, then the program runs but when client2 calls client1.message(), the message() method gets called for client2 and throws a NullPointer at this point.
I was looking at this link: http://www.exampledepot.com/egs/java.rmi/args_Args.html, which gave me a hint that it should implement Remote but not Serialization to pass by reference. I am not sure why the program is complaining in my case.
I really appreciate any help I can get. I've been trying to fix this problem for a while and I can't seem to find any solution.
Thank you very much!
you need to export Client and send the stub to the server
edit: this should work, it should the same way you exported the server (but without using the rmiregistry)
server.register((RMIClientIntf) UnicastRemoteObject.exportObject(client,0), name);
You can't just pass arbitrary references around via RMI. Client would have to be either Serializable, so it gets passed entire to the target, or an exported remote object itself, so a remote reference to it gets passed and it stays put - i.e. it is a callback.
EDIT: as the latter appears to be your intention, all you need to to is make Client extend UnicastRemoteObject.
There is an excellent RMI Trail as part of the Oracle/Sun Java Tutorials.