Spring MVC: Adding JAXB to the classpath so that it automatically serializes XML - spring

According to Spring MVC documentation, <mvc:annotation-driven/> configures support for JSON if Jackson is in the classpath, and support for XML if JAXB is present in the classpath. Simply by adding a Jackson dependency to my pom.xml, I get JSON support to work! (see: Ajax Simplification in Spring 3.0)
However, after trying to access the same service with accept header "application/xml", I get a 406 Not Acceptable response. What's the simplest way to get JAXB in the classpath? What is necessary to enable support for XML MarshallingHttpMessageConverter?
Update
Taking a look at AnnotationDrivenBeanDefinitionParser, I can see what defines if "jaxb2Present". I set a breakpoint around line 179 to see if the Jaxb2RootElementHttpMessageConverter is indeed being registered like the MappingJacksonHttpMessageConverter is. It isn't...
What's the simplest way to add JAXB to the classpath to make it automatically serialize my XML requests?

It should work. Make sure that the object being returned has #XmlRootElement annotation as required by JAXB.

If you're using Java 6, JAXB is already on the classpath. If you're using Java 5, you'll need to add a reference implementation yourself.
If you're using Maven, you can add to your pom.xml:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2</version>
</dependency>

Related

Is Zonky embedded database supported for Spring boot 3.0 version?

I am trying to migrate my application from spring boot 2.7.2 to 3.0.0 version.
On running integration test case, I am getting below error :
java.lang.NullPointerException: Cannot invoke "org.hibernate.metamodel.mapping.JdbcMapping.getJdbcValueBinder()" because "jdbcMapping" is null
Hibernate ORM core version is 6.1.5.Final.
Could someone please guide if they have used zonky libraries with spring boot 3.0 ?
I have added below dependencies in pom.xml :
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-database-spring-test</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-postgres</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
In case the test class uses a spring context that already contains a data source bean, the data source bean will be automatically replaced with a testing data source. The newly created data source bean will be injected into all related components, and you can also inject it into a test class.

Cannot construct instance of `reactor.core.publisher.Mono` Spring Cloud OpenFeign and Spring boot 2

Goal: migration from Spring Boot 1.x (webMvc) to version 2 (webFlux) and Spring Cloud Edgware SR2 to FinchleyM8 (awaiting release version).
Problem: Feign -> OpenFeign. OpenFeign under the hood uses RxJava but WebFlux - Reactor3. At the current moment when I using Mono as returned type, I have got an error:
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class reactor.core.publisher.Mono]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of reactor.core.publisher.Mono (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
Code example:
#FeignClient(name = "thirdpartyresource", url = "${third.party.resource.url}")
public interface ThirdPartyResource {
#PostMapping(value = "/validate", consumes = APPLICATION_FORM_URLENCODED_VALUE)
Mono<ValidationResultDto> validate(MultiValueMap multiValueMap); // WORKS BAD
// Single<ValidationResultDto> validate(MultiValueMap multiValueMap); WORKS WELL
}
Question:
Do I need to create my own converter Single to Mono or it's some problems of spring-cloud-starter-openfeign and all should work OOTB?
The reactor.core.publisher.Mono belongs to the spring-boot-starter-webflux jar.
Get the latest version of it from the mvn repository.
Then add it to your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.5.3</version>
</dependency>
Also do remove spring-boot-starter-web from your pom.xml, just in case if you have it.
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>-->
This fixed the issue!
You can use those methods to adapt:
For Single<T> rxJavaSingle
Mono.from(RxReactiveStreams.toPublisher(rxJavaSingle))
For Completable rxJavaCompletable
Mono.from(RxReactiveStreams.toPublisher(rxJavaCompletable))

Prevent XXE (External Entity Processing) Attack with JAXB + Spring RESTful Web Services

I know that we can prevent the XXE attack by setting the property IS_SUPPORTING_EXTERNAL_ENTITIES in the abstract class XMLInputFactory to false in JAXB.
I have also seen this stackoverflow answer.
My question here is,
How do I create a instance of XMLInputFactory and set this IS_SUPPORTING_EXTERNAL_ENTITIES property to false when the spring application loads up. And that particular XMLInputFactory instance should only be used for all the JAXB conversion for all the classes that uses javax.xml.bind.annotation package.
Spring uses RequestMappingHandlerAdapter which is an AbstractHandlerMethodAdapter that supports HandlerMethods with the signature -- method argument and return types, defined in #RequestMapping.
There are 7 seven HttpMessageConverters and one of them is Jaxb2RootElementHttpMessageConverter
Jaxb2RootElementHttpMessageConverter is from the spring-web package.
From 3.2.8 version of spring-web onwards Jaxb2RootElementHttpMessageConverter sets the processExternalEntities to false which in turn sets the XMLInputFactory property IS_SUPPORTING_EXTERNAL_ENTITIES to false.
Refer : Jaxb2RootElementHttpMessageConverter from Spring
Answer use
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>

Conflict between Spring data MongoDb and Elasticsearch

I started a project in which I use both Mongo, Elasticsearch and spring boot.
With either technologies by itself, the project works just fine. However with both together, they conflict. I saw this particular article that seemed to be similar to my issue.
https://jira.spring.io/browse/DATAES-57
So I tried it out and it the problem is still there.
I put these on the Main class
#EnableAutoConfiguration(exclude = MongoRepositoriesAutoConfiguration.class)
#EnableMongoRepositories(basePackages = "com.searchizi.mongo.repository")
#EnableElasticsearchRepositories(basePackages = "com.searchizi.elasticsearch.repository")
#ComponentScan
public class Application implements CommandLineRunner { … }
A shortened form the the exception trace is this
The class SearchiziUser is in the com.searchizi.mongo.model package. It is not on the Elasticsearch scan path.
Caused by: java.lang.IllegalArgumentException: Unable to identify index name. SearchiziUser is not a Document. Make sure the document class is annotated with #Document(indexName="foo")
at org.springframework.util.Assert.isTrue(Assert.java:65)
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.getPersistentEntityFor(ElasticsearchTemplate.java:869)
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.createIndexIfNotCreated(ElasticsearchTemplate.java:684)
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.createIndex(ElasticsearchTemplate.java:135)
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.createIndex(AbstractElasticsearchRepository.java:80)
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.<init>(AbstractElasticsearchRepository.java:72)
at org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository.<init>(SimpleElasticsearchRepository.java:36)
The scanning for each repository type should be separated but apparently it is not. Any idea what to do?
This is clearly a bug in Spring Data Elasticsearch as it seems to scan for domain types in packages it actually shouldn't. I filed DATAES-?? for you. Also, I filed a ticket so that Spring Data Elasticsearch supports the new multi-store configuration improvements so that you shouldn't have to explicitly configure separate packages.
On a side note, excluding the auto-configuration is not necessary if you set up #EnableMongoRepositories as it will automatically disable Spring Boot's auto-configuration.
I faced this exception and I resolved by change version of elasticsearch and mongodb lib versions
<!-- Spring data mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.10.0.RELEASE</version>
</dependency>
<!-- mongodb java driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
</dependency>
<!-- ELASTICSEARCH -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>

Why doesn't Spring 3.1 automatically use Jackson when POST header Content-Type=application/json?

No configuration or annotation is needed when setting request header "Accept=application/json"
It's almost automatic. Referring to
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-config-enable
Jackson is automatically selected and registered when it is in the classpath (i.e. pom.xml) and you use mvc:annotation-driven in your context config.
It does work automatically - in my controller I used an incorrect annotation - I used #RequestParam - it must be #RequestBody
In my situation, I fixed it with using another source for Jackson, because #RequestBody does not converted to the type I expect.
Instead of Codehause Jackson, I use now fasterxml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>

Resources