RestTemplate "no suitable HttpMessageConverter" - spring

i realize that something wired goes on with a project i try to create. I'm using the RestTemplate. And i'm trying to connect with a server and retrieve data. All went good until the time i decide to broke my program in more than one controller classes. Look what i did. In each one of these new classes i insert at each one of them:
RestTemplate restTemplate= new RestTemplate();
In order to retrieve data i'm using the JAXB annotations only(for data binding) and i can retrieve whatever i want. But when i'm trying to execute this line of code in the new class:
ResponseEntity<AClass> result = restTemplate.exchange("url",
HttpMethod.GET, entity, AClass.class);
I'm taking this exception: RestClientException "Could not extract response: no suitable HttpMessageConverter found for response type [AClass] and content type [application/xml]"
If i put it back in the previous class can be executed without problem. Really i don't understand why. Probably because i'm using in the new class a new RestTemplate.I try to declare different RestTemplates and also to declare this way:#Autowired but the problem remains. Should i declare something new in the dispatcher servlet?Moreover can i call in many classes the object restTemplate(RestTemplate restTemplate=new RestTemplate()). Should i declare it in a specific class and call it from there? What should i do?I expect your propositions.

How did you previously have your restTemplate instance set up? You have to register a MarshallingHttpMessageConverter with the RestTemplate instance, or it won't know how to unmarshal the XML. Something like this:
Jaxb2Marshaller jaxbMarshaller = new Jaxb2Marshaller();
// Make sure context paths includes AClass's package
jaxbMarshaller.setContextPaths("com.example.generated");
MarshallingHttpMessageConverter converter = new
MarshallingHttpMessageConverter(jaxbMarshaller, jaxbMarshaller);
restTemplate.setMessageConverters(Arrays.<HttpMessageConverter<?>> asList(converter));

Related

Spring: How to publish a multipart/form-data request to a Rabbit Queue

The application has an endpoint that consumes multipart/form-data and maps it to a MultipartFile obj. From there, we attempt to upload the file to the vendor. If its successful, nothing else occurs other than a HTTP.200 series
If there is a failure, we want to publish a message to a Rabbit Queue where fields in the message include things like "endpoint", "data", "headers" so that we can consume the messages and hit the endpoint at a later date.
The problem is that I can't deserialize the MultipartFile. Ive tried using ByteArrayResource as well but get the error No serializer found for class java.io.ByteArrayInputStream
Is there a better way to do this?
Also doing this approach because there are multiple endpoints that take in a file in different conventions, so being able to replicate the request and not have logic and just recall the endpoint is ideal
Ultimate question: How can I write value as string on a ByteArrayResource or MultipartFile obj with Jackson
Wouldn't it be easier to save the file to disk and send the path to the queue?
In any cases, ByteArrayResource should work if you add the converter:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter = new
MappingJackson2HttpMessageConverter(mapper);
return converter;
}

How to access/read objects inside Itemreader/StaxEventItemReader correctly?

I am new to the spring batch and I have an application where for example an xml-file of flights is read and saved to a database. The whole process is already working, but due to a certain use case I also need to access the data inside the reader object (ItemReader), should it is possible.
Down there is the reader-method. It is not about this method in particular, but as mentioned it is about ItemReader.
#Bean
public StaxEventItemReader<Flight> flightReader() {
StaxEventItemReader<Flight> reader = new StaxEventItemReader<Obj>();
reader.setResource(ressource);
reader.setFragmentRootElementName("flight");
Map<String, String> aliases = new HashMap<String, String>();
aliases.put("flight", Flight.class);
XStreamMarshaller xStreamMarshaller = new XStreamMarshaller();
xStreamMarshaller.setAliases(aliases);
reader.setUnmarshaller(xStreamMarshaller);
return reader;
}
How can I access the flight objects inside the reader (StaxEventItemReader) object?
I actually tried to use the read() method (Spring doc ItemReader), but I am always getting NullPointerExceptions.
If the read() method is the correct way, how can you access the flight objects inside ItemReader correctly?
If not, are there other ways?
There is more than one way to access the items. It really depends on what you want to do with them:
If you only want to have a look without manipulating the items, you can implement an ItemReadListener with its afterRead method, and add the listener to your step.
The items are passed to the processor. So you can operate on them there.
You can extend the class StaxEventItemReader and override the read method to include additional logic.
If you prefer composition over inheritance, you can write a new reader that uses a StaxEventItemReader as a delegate.

Spring Boot / Kafka Json Deserialization - Trusted Packages

I am just starting to use Kafka with Spring Boot & want to send & consume JSON objects.
I am getting the following error when I attempt to consume an message from the Kafka topic:
org.apache.kafka.common.errors.SerializationException: Error deserializing key/value for partition dev.orders-0 at offset 9903. If needed, please seek past the record to continue consumption.
Caused by: java.lang.IllegalArgumentException: The class 'co.orders.feedme.feed.domain.OrderItem' is not in the trusted packages: [java.util, java.lang]. If you believe this class is safe to deserialize, please provide its name. If the serialization is only done by a trusted source, you can also enable trust all (*).
at org.springframework.kafka.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.java:139) ~[spring-kafka-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.kafka.support.converter.DefaultJackson2JavaTypeMapper.toJavaType(DefaultJackson2JavaTypeMapper.java:113) ~[spring-kafka-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.kafka.support.serializer.JsonDeserializer.deserialize(JsonDeserializer.java:218) ~[spring-kafka-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.apache.kafka.clients.consumer.internals.Fetcher.parseRecord(Fetcher.java:923) ~[kafka-clients-1.0.1.jar:na]
at org.apache.kafka.clients.consumer.internals.Fetcher.access$2600(Fetcher.java:93) ~[kafka-clients-1.0.1.jar:na]
I have attempted to add my package to the list of trusted packages by defining the following property in application.properties:
spring.kafka.consumer.properties.spring.json.trusted.packages = co.orders.feedme.feed.domain
This doesn't appear to make any differences. What is the correct way to add my package to the list of trusted packages for Spring's Kafka JsonDeserializer?
Since you have the trusted package issue solved, for your next problem you could take advantage of the overloaded
DefaultKafkaConsumerFactory(Map<String, Object> configs,
Deserializer<K> keyDeserializer,
Deserializer<V> valueDeserializer)
 and the JsonDeserializer "wrapper" of spring kafka
JsonDeserializer(Class<T> targetType, ObjectMapper objectMapper)
Combining the above, for Java I have:
new DefaultKafkaConsumerFactory<>(properties,
new IntegerDeserializer(),
new JsonDeserializer<>(Foo.class,
new ObjectMapper()
.registerModules(new KotlinModule(), new JavaTimeModule()).setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setDateFormat(new ISO8601DateFormat()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false))));
Essentially, you can tell the factory to use your own Deserializers and for the Json one, provide your own ObjectMapper. There you can register the Kotlin Module as well as customize date formats and other stuff.
Ok, I have read the documentation in a bit more detail & have found an answer to my question. I am using Kotlin so the creation of my consumer looks like this with the
#Bean
fun consumerFactory(): ConsumerFactory<String, FeedItem> {
val configProps = HashMap<String, Any>()
configProps[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = bootstrapServers
configProps[ConsumerConfig.GROUP_ID_CONFIG] = "feedme"
configProps[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java
configProps[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = JsonDeserializer::class.java
configProps[JsonDeserializer.TRUSTED_PACKAGES] = "co.orders.feedme.feed.domain"
return DefaultKafkaConsumerFactory(configProps)
}
Now I just need a way to override the creation of the Jackson ObjectMapper in the JsonDeserializer so that it can work with my Kotlin data classes that don't have a zero-argument constructor :)

Possible bug in ResourceHttpMessageConverter

I've been experiencing a strange problem using the ResourceHttpMessageConverter in the latest Spring 3.2.4 version. I have an annotated controller that returns a Resource, in specific a UrlResource. This UrlResource is nothing more than a Request to another remote server that serves a pdf file. Usually the pdf is a small file (less than 1MB) but under some circumstances is larger. In case the file is large the client that contacts to my Controller can't download the file resulting in a connection closed error. The code I am using is the following
#Controller
#PreAuthorize(value = "isAuthenticated()")
public class TestController {
#ResponseBody
#RequestMapping(value="/report/", method = RequestMethod.GET,
produces = "application/pdf")
public Resource getReport() {
//Ignore the getResource method, it is not the problem
//this method returns an object of type UrlResource
return this.getResource();
}
}
Although there is a workaround using the StreamUtils class to copy the InputStream from the UrlResource to the OutputStream of the HttpServletResponse, I wanted to know for sure if there is anything else I could do to avoid that, and rely on the Spring MessageConverter infrastructure rather than reimplementing the same logic in my controller. Is there any spring developer around that can point me in the right direction if it is possible, or if this is a bug let me know so I can report it. Thanks!

Parsing a POJO to JSON using JAX-RS and not using any speific implemnation code

I was looking at internals of jersey, on how it converts a simple POJO to Json. Jersey has an interface Providers, which will provide list of contextResolvers given the class and mediaType. once we get the contextResolver, we can get the Context and Marshaller from it, which can used to get the json string, like show below.
lets assume we want to serialize the Pojo "obj". the code will look like follows
Providers ps = ...
ContextResolver<JAXBContext> resolver = ps.getContextResolver(obj.getClass(), MediaType.APPLICATION_JSON_TYPE);
JAXBContext ctx = resolver.getContext(obj.getClass());
ctx.createMarshaller().marshal(obj, writer);
By above way we can convery any POJO which has a valid context resolver to json. but the question is how do we get the handler for Providers.
PS: i have not compiled this code, but from what i can see from source this is what jersey does. On why i am doing all this stuff, so that we can convert a object to JSON directly with JAX-RS apis. instead of using any implementation code.
In a JAX-RS resource clas, use the #Context annotation to tell Jersey to inject the producers:
#Context Producers producers;
So your question is : "how to find providers" ?
You have to write code to find classes in the classpath which are Annotated with #Provider.

Resources