Spring offers several ways to convert POJO to XML through HttpMessageConverter. However, I am having quite a bit of difficulty finding one that supports custom namespace with prefix.
For example from
public class Student {
String name;
String address;
Integer score;
}
To
<?xml version="1.0" encoding="UTF-8"?>
<foo:Student xmlns:foo="http://schemas.foo.com/student">
<foo:name>Some Name</foo:name>
<foo:address>Address</foo:address>
<foo:score>95</foo:score>
</foo:Student>
I was happily using MappingJackson2HttpMessageConverter with jackson-dataformat-xml until I realized that it does not support custom prefix.
Then I looked into using MarshallingHttpMessageConverter with XStreamMarshaller, only to find out that XStream does not support custom prefix either.
Can anyone refer me to a example how I can serialize POJO to xml with custom namespace prefix? Thanks.
I have managed to resolve similar problem for Jackson. First you have to use woodstox XML processor.
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.4.0</version>
</dependency>
Than I have added namespace perfix/uri mapping this way:
XmlMapper mapper = new XmlMapper();
// override default instance of WstxOutputFactory
mapper.getFactory().setXMLOutputFactory(new WstxOutputFactory() {
#Override
public XMLStreamWriter createXMLStreamWriter(Writer w) throws XMLStreamException {
mConfig.setProperty(WstxInputProperties.P_RETURN_NULL_FOR_DEFAULT_NAMESPACE, true);
XMLStreamWriter result = super.createXMLStreamWriter(w);
result.setPrefix("xlink", "http://www.w3.org/1999/xlink");
return result;
}
});
For sure this is not elegant soultion but I am not sure if there is any other way. I hope Jackson will add api support for prefixes in future release.
I guess however in your case default namespace with prefix is needed and this seems to be more difficult because Jackson does not support default namespace (https://github.com/FasterXML/jackson-dataformat-xml/issues/18) and even using class inheritance with #JacksonXmlRootElement(namespace="http://xmlns.uri.com") you still would need to annotate each property with #JacksonXmlProperty(namespace="http://xmlns.uri.com")
Related
I have defined a rest endpoint method as:
#GetMapping("/get")
public ResponseEntity getObject(#Valid MyObject myObject){....}
This maps request parameters to MyObject.
MyObject is defined as(with lombok, javax.validation annotations):
#Value
#AllArgsConstructor
public class MyObject {
#Min(-180) #Max(180)
private double x;
#Min(-90) #Max(90)
private double y;
}
But validations are not working. Even with values out of prescribed range, request doesn't throw error and goes well.
If you on a version of Spring Boot > 2.3 it now states
Validation Starter no longer included in web starters
... you’ll need to add the starter yourself.
i.e.
For Maven builds, you can do that with the following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
For Gradle, you will need to add something like this:
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
Please refer to https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#validation-starter-no-longer-included-in-web-starters
Annotate your controller with org.springframework.validation.annotation.Validated
I see a couple of things here that you should fix. Let's start talking about the REST standard, the first rule is to think in endpoints as representation of resources, not operations, for example, in your code, I presume the MyObject class represents a Point (you should refactor the class to have a proper name), then the path value for the getObject can be "/point". The operations are mapped on the HTTP method, accordingly:
GET: Obtain info about a resource.
POST: Create a resource.
PUT: Update a resource.
DELETE: Delete a resource.
In getObject you're expecting to receive an object. The get method according to the REST standards means you want to retrieve some data, and usually you send some data included in the url like ../app-context/get/{id}, here the id is a parameter that tells your controller you want some info belonging to an id, so if you would invoke the endpoint like as ../app-context/get/1 to get info of some domain object identified by the number 1.
If you want to send data to the server, the most common HTTP method is a POST.
According to this, at design level you should:
Give a meaningful name to the MyObject class.
Check the operation you want to make in the getObject.
Assign a path to getObject representing a resource.
At code level, with the above comments, you could change this as:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class MyObject {
#Min(-180) #Max(180)
private double x;
#Min(-90) #Max(90)
private double y;
}
#PostMapping("/point")
public ResponseEntity savePoint(#RequestBody #Valid MyObject myObject) {...}
I will explain the changes:
Add #PostMapping to fulfill the REST standard.
Add #RequestBody, this annotation take the info sent to the server and use it to create a MyObject object.
Add #NoArgsConstructor to MyObject, by default, the deserialisation use a default constructor (with no arguments). You could write some specialised code to make the things work without the default constructor, but thats up to you.
I just had to add the following dependency to get the validations working.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
I have a Spring Boot app that is modeling ActityStreams objects and for the most part Jackson's Polymorphic Deserialization works well.
There are 'objects' in the JSON which are references (links) and not JSON objects with type information. For instance
"actor":"https://some.actors.href/ rather than
"actor":{
"type":"Actor",
"name":"SomeActor"
}
I've written custom deserializers and and placed them on the fields to deal with this
#JsonDeserialize (using = ActorOrLinkDeserializer.class)
private Actor actor;
However my ActorOrLinkDeserializer is instantiated but never called and Jackson complains with Missing type id when trying to resolve subtype of [simple type, class org.w3.activity.streams.Actor]: missing type id property 'type' (for POJO property 'actor') which is from the polymorphic deserializer.
It appears that the polymorphic deserialization code takes precedence over my local #JsonDeserialize annotation and I need a way to force my code to run first.
I've tried using my own ObjectMapper rather than Boot's and there's no difference.
I'd appreciate pointers and suggestions.
It turns-out there's a fairly simple solution to this problem using a DeserializationProblemHandler.
What I've implemented that works for all test cases so far is
1.
objectMapper.addHandler(new DeserProblemHandler());
or register with Spring Boot.
2.
public class DeserProblemHandler extends DeserializationProblemHandler {
public JavaType handleMissingTypeId(DeserializationContext ctxt, JavaType baseType, TypeIdResolver idResolver, String failureMsg) {
return TypeFactory.defaultInstance().constructType(baseType.getRawClass());
}
}
Add a constructor to each of the polymorphic classes that takes a string argument which is the href.
I am working with Jersey Web services (2.23) and use POJO mapping for the JSON-to-Object mapping (Jersey-media-moxy). I created a class as follows:
public class DataPush {
public String asset;
public String timestamp;
public Map<String,String> aspects;
}
I expected that instances of this object have the following structure:
{"asset":"abc","timestamp":"xxx","aspects":[{"key":"sdfasd","value":"sdfsd"},{"key":"sdddfasd","value":"sdfddsd"}]}
Indeed, a further element "entry" is generated:
{"asset":"sdf","timestamp":"sdfsd","aspects":{"entry":[{"key":"sdfasd","value":"sdfsd"},{"key":"sdddfasd","value":"sdfddsd"}]}}
What is the most easiest way to get rid of the "entries" element?
I know I could write my own mapping, however I hope that there is a easy solution to manage this..
You can go to topic :
Jackson JSON – Converting JSON to Map on journaldev.com.
https://www.journaldev.com/2324/jackson-json-java-parser-api-example-tutorial
I am trying to instantiate a resolver from spring-cloud-aws-messaging, specifically the NotificationMessageArgumentResolver. The problem is that it takes a MessageConvertor as an argument. So, this is what I have so far:
private NotificationMessageArgumentResolver notificationMessageArgumentResolver() {
new NotificationMessageArgumentResolver(this.messageConvertor);
}
To get the messageConvertor, I have tried:
#Autowired
public MvcConfig(MessageConvertor messageConvertor) {}
#Autowired
public MvcConfig(MappingJackson2MessageConverter messageConvertor) {}
but I get the same error either ways no bean found. The documentation is simply asking to use the XML:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<ref bean="notificationResolver" />
</mvc:argument-resolvers>
<aws-messaging:notification-argument-resolver id="notificationResolver" />
Which, according to the doc
registers three argument resolvers: NotificationStatusHandlerMethodArgumentResolver, NotificationMessageHandlerMethodArgumentResolver, and NotificationSubjectHandlerMethodArgumentResolver.
So, following the answer from How to use argument-resolvers using annotation in Spring boot?, I am able to get 2 of the 3 beans added, as they don't need any beans I cannot access, however I am not able to instantiate NotificationMessageArgumentResolver due to the lack of a MessageConvertor. I am expecting all my messages to come purely in JSON, so I do know exactly which MessageConvertor to use, which is the default one for JSON that ships with Spring Boot.
EDIT
The entire file, if anyone is interested: http://pastebin.com/tM471AEv
I wonder if you really need the NotificationMessageArgumentResolver as that is intended to be used when using messaging. As you can see it implements the HandlerMethodArgumentResolver from the org.springframework.messaging package.
I suspect that you want to use the NotificationMessageHandlerMethodArgumentResolver instead. Which is the HandlerMethodArgumentResolver for use with the web instead of messaging. Which is also registered when using <aws-messaging:notification-argument-resolver id="notificationResolver" />
I would also suggest to use the NotificationHandlerMethodArgumentResolverFactoryBean instead of 3 individual beans as that is also the class that is used internally by the namespace and annotation driven configuration.
Your configuration would look something like this.
#Bean
public NotificationHandlerMethodArgumentResolverFactoryBean notificationHandlerMethodArgumentResolverFactoryBean() {
return new NotificationHandlerMethodArgumentResolverFactoryBean();
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(notificationHandlerMethodArgumentResolverFactoryBean.getObject());
}
Firstly, I am newbie in Vaadin 7. I was just trying out some vaadin demo when I discovered the BeanFieldGroup.class. As I saw ,this class bound a field to a bean property. In the bean the properties are annotated with validation constraints annotations ( JSR 303 ). In this case my pom.xml include hibernate validator dependency:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.CR1</version>
</dependency>
I made ValidationMessage.properties file and put there some messages, ( with Hungarian characters ) and it has been saved UTF-8 format,for example :
validation.NotBlank=Árvíztűrő tükörfúrgép
And here is the annotated bean property:
#NotNull(message = "{validation.NotBlank}")
private String name = null;
I can see, when I change the field value to null, Vaadin show me my previous constraint error message, but with wrong character coding.
In other hand - without Vaadin, but Spring,I can use the next simple formula where the character coding is appropriate me ( as you can see I use Spring ReloadableResourceBundleMessageSource) :
private MessageSource MessageSource(){
ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
reloadableResourceBundleMessageSource.setCacheSeconds(5000);
reloadableResourceBundleMessageSource.setFallbackToSystemLocale(false);
reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");
Properties properties = new Properties();
properties.setProperty("fileEncodings", "UTF-8");
reloadableResourceBundleMessageSource.setFileEncodings(properties);
reloadableResourceBundleMessageSource.setBasename("classpath:/locales/messages");
return reloadableResourceBundleMessageSource;
}
#Bean
public LocalValidatorFactoryBean validator(){
LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
factory.setValidationMessageSource(MessageSource());
return factory;
}
My question is: Can Somebody tell me the right solution how do I configure hibernate validator or Vaadin to read property files with UTF-8 encoding ?
By default, ISO-8859-1 encoding is used when reading properties files. Characters not available in that encoding must be converted using Unicode escapes ("\u1234"), e.g. using the native2ascii tool. See this answer to a related question for some more details.
Alternatively, you could plug in a custom ResourceBundleLocator which reads properties using UTF-8 encoding. The Hibernate Validator reference guide describes how to do this. As a starting point, you could take PlatformResourceBundleLocator and adapt it as per your requirements.
Vaadin's BeanFieldGroup uses another Vaadin class BeanValidator for JSR-303 validation. If you take a look at it's source code at BeanValidator.getJavaxBeanValidator() and getJavaxBeanValidatorFactory() methods, wou will see that it's building it's own Validator and ValidatorFactory instances. You'll need to subclass it and override the getJavaxBeanValidatorFactory() method with one that uses a ValidatorFactory obtained from your Spring context, which is properly set up to use Spring's own UTF-8 encoded MessageSource as you already configured it in your example. It will also help you with debugging as Spring's MessageSource can be reloadable, which is a huge saver.
EDIT: following a question in comments on how to override with subclassing I realized that with the current state of this part of the Vaadin API as of version 7.5.9, I can't do it elegantly. Since we can't do it elegantly we could do it the quick and dirty way by reflection with this hack implemented as a spring component:
#Component
public class VaadinValidationHack implements InitializingBean {
#Autowired
private ValidatorFactory validatorFactory;
protected void hack() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field field = BeanValidator.class.getDeclaredField("factory");
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(null, validatorFactory);
}
#Override
public void afterPropertiesSet() throws Exception {
hack();
}
}