No message body writer has been found for response class MyException - jax-rs

I'm using Apache-cxf to implement Restful web services. I'm using ExceptionMapper to build the response object in case if exception occurs. I'm getting below error if any exception occurs.
"No message body writer has been found for response class MyException."
I could find some of the post which suggest to custom Writer which implements MessageBodyWriter, but i'm not very clear why do i need a custom writer if entity object (ErrorInfo) which is passed for building response is the jaxb object. This might be a very silly question but just want to understand.
#Provider
public class MyExceptionMapper implements
ExceptionMapper<MyException> {
#Override
public Response toResponse(MyException ex) {
Response.Status statusCode = exceptionMap.get(ex.getClass());
ErrorInfo errorInfo=new ErrorInfo();
errorInfo.setErrorCode(ex.getErrorCode());
errorInfo.setErrorMessage(ex.getMessage());
return Response.status(statusCode).entity(ex).build();
}
}
#XmlRootElement(name = "errorInfo")
#XmlType(propOrder = { "errorCode", "errorMessage"})
public class ErrorInfo {
private String errorCode;
private String errorMessage;
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}

Had the same problem, for me setting the content type explicitly solved the issue:
return Response.status(statusCode).entity(ex).type(MediaType.APPLICATION_JSON).build();

Related

How to unwrap Custom RuntimeException from Json Mapping Exception

In a spring data rest project i use a custom RuntimeException to be called in a custom Deserializer
public class LocalDateDeserializer extends StdDeserializer<LocalDate> {
...
#Override
public LocalDate deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException, JsonProcessingException {
String date = jsonparser.getText();
String name = jsonparser.getCurrentName();
try {
return LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE);
} catch (DateTimeParseException e) {
throw new ApiJacksonException("error on: " + name);
}
}
}
My User.class
#Data
#NoArgsConstructor
public class User extends Auditing implements Serializable {
private static final long serialVersionUID = 1L;
...
#DateTimeFormat(iso = ISO.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
#JsonDeserialize(using = LocalDateDeserializer.class)
#JsonSerialize(using = LocalDateSerializer.class)
private LocalDate birthdate;
}
When i send a POST request with a wrong date format the #ControllerAdvice catch the custom RuntimeException
But when i send a PATCH request with a wrong date format it seams that the RuntimeException is wrapped by the JsonMappingException and can't be catched by the #ControllerAdvice
in the properties file i have set
spring.jackson.deserialization.wrap-exceptions = false
Have i missed some thing!
Resolved, indeed an update request (patch/put) with an invalid Date format will fire a HttpMessageNotReadableException that wraps the custom RuntimeException, in #ControllerAdivce we have to override handleHttpMessageNotReadable
#Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
if(ex.getCause() instanceof ApiJacksonException) {
// execute custom code...
}
return super.handleHttpMessageNotReadable(ex, headers, status, request);
}

RabbitMQ not serialize message, error convert

I've seen some related questions here, but none worked for me, the rabbit will not serialize my message coming from another application.
Caused by: org.springframework.amqp.AmqpException: No method found for class [B
Below my configuration class to receive the messages.
#Configuration
public class RabbitConfiguration implements RabbitListenerConfigurer{
public final static String EXCHANGE_NAME = "wallet-accounts";
public final static String QUEUE_PAYMENT = "wallet-accounts.payment";
public final static String QUEUE_RECHARGE = "wallet-accounts.recharge";
#Bean
public List<Declarable> ds() {
return queues(QUEUE_PAYMENT, QUEUE_RECHARGE);
}
#Autowired
private ConnectionFactory rabbitConnectionFactory;
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(rabbitConnectionFactory);
}
#Bean
public TopicExchange exchange() {
return new TopicExchange(EXCHANGE_NAME);
}
private List<Declarable> queues(String ... names){
List<Declarable> result = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
result.add(makeQueue(names[i]));
result.add(makeBinding(names[i]));
}
return result;
}
private static Binding makeBinding(String queueName){
return new Binding(queueName, DestinationType.QUEUE, EXCHANGE_NAME, queueName, null);
}
private static Queue makeQueue(String name){
return new Queue(name);
}
#Bean
public MappingJackson2MessageConverter jackson2Converter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
return converter;
}
#Bean
public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(jackson2Converter());
return factory;
}
#Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(myHandlerMethodFactory());
}
}
Using this other configuration, the error is almost the same:
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to resolve class name. Class not found [br.com.beblue.wallet.payment.application.accounts.PaymentEntryCommand]
Configuration:
#Configuration
public class RabbitConfiguration {
public final static String EXCHANGE_NAME = "wallet-accounts";
public final static String QUEUE_PAYMENT = "wallet-accounts.payment";
public final static String QUEUE_RECHARGE = "wallet-accounts.recharge";
#Bean
public List<Declarable> ds() {
return queues(QUEUE_PAYMENT, QUEUE_RECHARGE);
}
#Autowired
private ConnectionFactory rabbitConnectionFactory;
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(rabbitConnectionFactory);
}
#Bean
public TopicExchange exchange() {
return new TopicExchange(EXCHANGE_NAME);
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
private List<Declarable> queues(String ... names){
List<Declarable> result = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
result.add(makeQueue(names[i]));
result.add(makeBinding(names[i]));
}
return result;
}
private static Binding makeBinding(String queueName){
return new Binding(queueName, DestinationType.QUEUE, EXCHANGE_NAME, queueName, null);
}
private static Queue makeQueue(String name){
return new Queue(name);
}
}
Can anyone tell me what's wrong with these settings, or what's missing?
No method found for class [B
Means there is a default SimpleMessageConverter which can't convert your incoming application/json. It is just not aware of that content-type and just falls back to the byte[] to return.
Class not found [br.com.beblue.wallet.payment.application.accounts.PaymentEntryCommand]
Means that Jackson2JsonMessageConverter can't convert your application/json because the incoming __TypeId__ header, representing class of the content, cannot be found in the local classpath.
Well, definitely your configuration for the DefaultMessageHandlerMethodFactory does not make sense for the AMQP conversion. You should consider to use SimpleRabbitListenerContainerFactory bean definition and its setMessageConverter. And yes, consider to inject the proper org.springframework.amqp.support.converter.MessageConverter implementation.
https://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#async-annotation-conversion
From the Spring Boot perspective there is SimpleRabbitListenerContainerFactoryConfigurer to configure on the matter:
https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/htmlsingle/#boot-features-using-amqp-receiving

Mocking the static method with Mockito

I am trying to mock static method using powermock.
Below is my code:
public class Helper{
public static User getLoggedInUser(HttpServletRequest request) throws NotFoundException {
String access = request.getHeader("Authorization");
if(access == null || access.isEmpty()) {
throw new Exception("Access is null");
}
User user = new User();
return user;
}
}
And this is the controller function from where i am calling the static method getUser:
#RequestMapping(value = "user/userInfo/{Id}", method = RequestMethod.GET, headers = "Accept=application/json")
public #ResponseBody
ResultDTO getUser(#PathVariable("Id") Integer Id, HttpServletRequest request) throws NotFoundException, UnauthorizedException {
Integer userID = -1;
User user = Helper.getLoggedInUser(request);
if(user != null){
userID = user.getUserId();
}
//do something
}
And this is my test class:
//#RunWith(PowerMockRunner.class)
//#PrepareForTest(Helper.class)
public class CustomerControllerNGTest {
#InjectMocks
private userController instance = new PaymentCustomerController();
public PaymentCustomerControllerNGTest() {
}
#BeforeClass
public void setUpClass() throws Exception {
}
#AfterClass
public static void tearDownClass() throws Exception {
}
#BeforeMethod
public void setUpMethod() throws Exception {
try{
MockitoAnnotations.initMocks(this);
}catch(Exception ex){
System.out.println(ex.getMessage());
}
try{
mockMvc = MockMvcBuilders.standaloneSetup(instance).build();
// mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}catch(Exception ex){
System.out.println(ex.getMessage());
}
}
#AfterMethod
public void tearDownMethod() throws Exception {
}
#Test
public void testGetUserInfo() throws Exception {
User user = new User();
user.setUserId(1234);
HttpServletRequest request = mock(HttpServletRequest.class);
//this is for the static method
PowerMockito.mockStatic(Helper.class);
**PowerMockito.when(Helper.getLoggedInUser(request)).thenReturn(user);**
//do something
}
}
Now whenever i am executing the test case, and whenever it is executing the lone marked with bold, it is going inside the static method and throwing the exception "Access is null" rather than mocking the method , it is executing the method. Any idea?
I also tried by uncommenting these lines:
//#RunWith(PowerMockRunner.class)
//#PrepareForTest(Helper.class)
but still same exception.
Thanks
Try to uncomment:
//#RunWith(PowerMockRunner.class)
//#PrepareForTest(Helper.class)
and use
Mockito.when(Helper.getLoggedInUser(request)).thenReturn(user);
I wrote blog post on topic, that contain links to working examples on GitHub. These use TestNg instead of JUnit, but this shouldn't matter.
EDIT
I would suggest to always use latest combination of Mockito and PowerMock available. Older combinations were often pretty buggy with confusing errors. Current latest combination is Mockito 1.9.5-rc1+, PowerMock 1.5+. Pre-1.5 versions of PowerMock wasn't Java7 compliant.

Deserialization of incoming message

Json is sent from the client to my api controller
Message
{"todo":{"title":"jo","isCompleted":false,"isDeleted":false,"testFK":null}}
I will list different consuming server side methods that should receive this message transformed into a object
public void Post(TaskEntity todo)
{
using (var context = new ToDoEntities())
{
context.Tasks.Add(todo.ToEf());
context.SaveChanges();
}
}
todo parameter is null.
public void Post(UpdateTodoInputMessage message)
{
using (var context = new ToDoEntities())
{
context.Tasks.Add(todo.todo.ToEf());
context.SaveChanges();
}
}
Message class
namespace MvcApplication1.Messages
{
[DataContract]
public class UpdateTodoInputMessage
{
[DataMember]
public TaskEntity todo { get; set; }
}
}
The todo property of the message class is null.
If I change the post method to a string then my client receives a 405 Method not allowed.
public void Post(string message)
{
using (var context = new ToDoEntities())
{
// context.Tasks.Add(todo.todo.ToEf());
// context.SaveChanges();
}
}
I am at a loss and would love some assistance as to how the deserialization of the string is taking place, and why I am getting these strange results.
The reason was that my Task Entity class didn't have a empty constructor

how to dynamically download a file using struts 2 annotations (passing variable into annotation)

im new to struts 2 and im asking if there's a way to pass a variable argument into struts 2 annotation.
here is what i already did but with no luck
public class DownloadFileAction extends ModuleGenericClass{
private InputStream inputStream;
private String fileName;
#Action(value="/downloadFile",results={
#Result(name="success",type="stream",params = {
"contentType",
"application/octet-stream",
"inputName","inputStream",
"bufferSize","1024","contentDisposition",
"filename=\"${fileName}\""})
})
public String execute() throws Exception {
fileName = "testing";
inputStream = //myInputStream
return SUCCESS;
}
public void setCourrierId(String courrierId) {
this.courrierId = courrierId;
}
public String getfileName() {
return fileName;
}
public void setfileName(String fileName) {
this.fileName = fileName;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
}
i searched on the net but i found only solutions with xml Struts and that is not what i want =(
Your filename getter method is named incorrectly, it should follow the JavaBean pattern:
public String getFileName() { ... }
OGNL's failing to call the getter; dynamic parameters work in annotations as they do in XML.