ObjectMapper ignoring configuration when annotations are present - java

My project is using application.properties file to set the property as following: spring.jackson.deserialization.fail-on-unknown-properties=true, which works in all cases but one:
class Model {
#JsonUnwrapped
public SubModel subModel;
}
simply commenting out the annotation causes ObjectMapper to fail as intended, but as soon as the annotation is added, the option set seems to be ignored.
How can I configure jackson to use annotations along with the config?

Due to logic needed to pass down unwrapped properties from parent context, there is no way to efficiently verify which properties might be legitimately mapped to child POJOs (ones being unwrapped), and which not.
As of now it is not possible to make jackson to fail on unknown property with unwrapping.
Issue is still open ,
https://github.com/FasterXML/jackson-databind/issues/650
How can I configure jackson to use annotations along with the config?
It is nothing to do with config or annotations, they are working fine.

Related

To provide nicer logging when a Spring property is invalid

Using a application.properties file my Spring Boot app can use some property values in it. A way to make sure a mandatory value must present is to add an annotation #Value for the property. The problem with this is the app fails miserably if the property value is not there in the properties file.
I am after a nicer less horrible way to say printing out a log line about "Property A is missing" instead of a whole stack trace. Is there a way to do this while still using #Value to initialise the properties? For example, property A is mandatory, an error is logged before app exits; property B is missing but not mandatory, a warning is logged and app continues.
If you can identify all property, then you can write a method in Application class with #Postconstruct, and inside your method, you can manually validate and log them
#Autowired
private Environment environment;
#PostConstruct
private void validateProperties() {
environment.getProperty(key);
.....
......
}
Alternatively, you can write your custom EnvironmentPostProcessor, and iterate all properties and log whichever is null/empty.
As you're using spring-boot consider creating a #ConfigurationProperties class rather than using the #Value annotation.
By doing that you can do your validations using Bean Validation, also in the same class, you can implement the interface InitializingBean and add extra validations/log messages as you with.
Follow this link on Spring's official docs to read more about #ConfigurationProperties.

set value to Cacheable annotation from property file

I'm using Spring Cacheable annotation and at the moment I'm struggling with a way of adding the cache name from property file.
I tried:
#Cacheable("${some.cache.name}")
and
#Cacheable("#{'${some.cache.name}'}")
There is a SPI to do that that is much more powerful than just using SpEL. You can implement CacheResolver and resolve cache instance(s) at runtime. You could use the annotated type or any name that is provided via the annotation.
You can specify the CacheResolver per annotation, at class-level using #CacheConfig or globally by implementing CacheConfigurer.
Check the documentation for more details

Automatic add Root Element in JAXB

In Jersey, how can I automatically add root in JAXB pojo?
I have my JAXB pojo
class Product {
private String name;
....
}
By default the generated json is
{
"name": "Burton Custom Freestlye 151",
}
I would like it to be
{
"product": {
"name": "Burton Custom Freestlye 151",
}
}
Note: What I mean by automatic is not creating separate class just to enclose another pojo.
This should be in serialization/deserialization into JSON.
Also I have other JSON don't use root element.
With Spring Boot, you can just configure an ObjectMapper as a Spring bean, and Spring Boot is set up where Jersey will use the mapper. The configuration property for the ObjectMapper to automatically add a root element is
SerializationFeature.WRAP_ROOT_VALUE
The default behavior is to take the class name and lower case it. If you want something different you can annotation the class with #XmlRootElement("newName") or #JsonRootName("newName"). To make a Spring bean just add the following in your configuration class
#Bean
public ObjectMapper mapper() {
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_NAME, true);
return mapper;
}
Note I think this (creating a Spring bean for the ObjectMapper) is only available starting from 1.4.0. If you are using a earlier version of Boot, you should just do this.
Also if you are expecting incoming JSON with the wrapped value, you will also want to unwrap it. You can do that with
DeserializationFeature.UNWRAP_ROOT_VALUE
Configure it the same way as above (passing true).
UPDATE
(Not very useful at this point, but maybe in the future)
Looking at the source for #JsonRootName, it seems Jackson has been planning on adding an alwaysWrap property in the annotation since 2.4. But I guess they have been delaying this. Not sure why. Maybe in the future it'll show up.

Is Spring's #Value annotation part of internationalization?

I am working on a project where internationalized messages are retrieved using the #Value annotation.
e.g.:
#Value("${email.newUser.subject}")
private String NEW_USER_SUBJECT;
#Value("${email.newUser.message}")
private String NEW_USER_MESSAGE;
However, as part of my investigation, it appears that the #Value annotation is used to get a property from a property file and does not link into to automatic lookup of the correct version of the message.properties. Therefore as I understand it, this is only working by coincidence because we have currently only a single message.properties file.
Can anyone in the know tell me if I have the correct understanding of the situation?
The Answer is No, the #Value annotation is not part of Internationalization. It's use in conjunction with Internationalization is an error and will break when you try to change the Local.

How to enable #Required?

How to enable the #Required annotation in Java (Spring 3.1) ? Not in a xml, but in through Java. Also under which annotation I put this enabling? Under #Feature (in #FutureConfiguration or #Bean (in #Configuration) ?
Edit:
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
Does this enables all annotations?
#anubhava's answer works, but he's referenced the Spring 2.0 manual, which is 5 years old.
In XML config, Spring 3.x has a more elegant approach: <context:annotation-config/>. This also enabled a whole other bunch of features that you'll probably want, whereas RequiredAnnotationBeanPostProcessor only enables a few.
See Spring 3.x manual.
If you're using #Bean-style config, then annotations like #Required should already be enabled, since that's how #Bean works. However, it's possible that this is a bug - Spring 3.1 is still in early beta, and big chunks of it are likely to be broken.
Unless you really know what you're doing, I strongly recommend sticking to 3.0.x.
From the Spring manual:
There is one last little (small, tiny)
piece of Spring configuration that is
required to actually 'switch on' this
behavior. Simply annotating the
'setter' properties of your classes is
not enough to get this behavior. You
need to enable a component that is
aware of the #Required annotation and
that can process it appropriately.
This component is the
RequiredAnnotationBeanPostProcessor
class. This is a special
BeanPostProcessor implementation that
is #Required-aware and actually
provides the 'blow up if this required
property has not been set' logic. It
is very easy to configure; simply drop
the following bean definition into
your Spring XML configuration.
<bean class=
"org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
Please check: http://static.springsource.org/spring/docs/2.0.x/reference/metadata.html
Use AnnotationConfigApplicationContext if you don't want to use XML:
Standalone application context,
accepting annotated classes as input -
in particular #Configuration-annotated
classes, but also plain #Components
and JSR-330 compliant classes using
javax.inject annotations. Allows for
registering classes one by one
(register(java.lang.Class...)) as well
as for classpath scanning
(scan(java.lang.String...)).
In case of multiple Configuration
classes, Bean methods defined in later
classes will override those defined in
earlier classes. This can be leveraged
to deliberately override certain bean
definitions via an extra Configuration
class.
Sample Code:
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
"com.mycompany.package1",
"com.mycompany.package2",
"com.mycompany.package3"
// etc.
);
applicationContext.refresh();

Categories

Resources