How to conditionally exclude property from a json response - java

I have a class pojo used to return a response to an API call in the rest controller
EmployeeResponse response = validationService.validate(request);
return new ResponseEntity<>(response, HttpStatus.OK);
However now we want to feature flag the controller class so that if a configuration property is not set, the response will not include a property. How can we do that?
public class EmployeeResponse {
private String firstName;
private String lastName
private String address; // don't want to include this if boolean flag is not set
}
EDIT: adding the controller code here to show that an object is returned without being serialized so I don't see how to fit objectMapper into that
#RestController
public class EmployeeController {
#PostMapping(value = "/validate", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<EmployeeResponse> get(final #RequestBody EmployeeRequest employeeRequest) {
MasterSubResponse response = validationService.validate(employeeRequest);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}

You can use Jackson Filter to control the serialization process. When using JSON format, Spring Boot will use an ObjectMapper instance to serialize responses and deserialize requests. The idea is to create custom filter where you will place business logic for conditionally rendering desired field from DTO. Then you should add that filter to object mapper.
To summarize,here are the steps youn need to follow :
Anottate your DTO class with #JsonFilter("myFilter")
Create implementation class for your custom filter
Create configuration class for ObjectMapper where you will set filter created in step 1.
Create your boolean flag in application.properties file
Step 1:
import com.fasterxml.jackson.annotation.JsonFilter;
#JsonFilter("myFilter")
public class EmployeeResponse {
private String firstName;
private String lastName;
private String address;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Step 2:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
public class CustomFilter extends SimpleBeanPropertyFilter implements PropertyFilter {
private boolean isSerializable;
#Override
public void serializeAsField
(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
throws Exception {
if (include(writer)) {
if (!writer.getName().equals("address")) {
writer.serializeAsField(pojo, jgen, provider);
return;
}
System.out.println(isSerializable);
if (isSerializable) {
writer.serializeAsField(pojo, jgen, provider);
}
} else if (!jgen.canOmitFields()) { // since 2.3
writer.serializeAsOmittedField(pojo, jgen, provider);
}
}
#Override
protected boolean include(BeanPropertyWriter writer) {
return true;
}
#Override
protected boolean include(PropertyWriter writer) {
return true;
}
public boolean isSerializable() {
return isSerializable;
}
public void setSerializable(boolean serializable) {
isSerializable = serializable;
}
}
Step 3:
import com.example.demo.filter.CustomFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ObjectMapperCofiguration {
#Value("${isSerializable}")
public boolean isSerializable;
#Configuration
public class FilterConfiguration {
public FilterConfiguration(ObjectMapper objectMapper) {
SimpleFilterProvider simpleFilterProvider = new SimpleFilterProvider().setFailOnUnknownId(true);
CustomFilter customFilter = new CustomFilter();
customFilter.setSerializable(isSerializable);
simpleFilterProvider.addFilter("myFilter", customFilter);
objectMapper.setFilterProvider(simpleFilterProvider);
}
}
}
Step 4 :
In application.properties file add following property :
isSerializable= false
Step 5:
Create Controller class to test it:
#RestController
public class RestSpringBootController {
#GetMapping(path = "/test")
public ResponseEntity<EmployeeResponse> test() throws JsonProcessingException {
EmployeeResponse employeeResponse = new EmployeeResponse();
employeeResponse.setAddress("addres");
employeeResponse.setFirstName("first");
employeeResponse.setLastName("last");
ResponseEntity<EmployeeResponse> responseEntity = ResponseEntity.ok(employeeResponse);
return responseEntity;
}
}
Finally, when you start your SpringBoot app, with boolean flag isSerializable set to false you should get following response:
If you set isSerializable flag to true and restart the app, you shoud see following response:

Related

Multiple yml files configuring in corresponding Configuration class (Spring Boot)

I have more than one yml files in Spring Boot in resource classpath location like following structure of Spring Boot. Initially I have written only for application-abc.yml and at the time all the values of this file was loading in their corresponding class but when I have added on another file application-xyz.yml then also it loads into their corresponding configuration classes but at this time only loading the values of application-xyz.yml in both the configuration classes. So, want help to configure values of both the files in their corresponding configuration files in a single build :
-src
-main
-java
-packages
-config
-ApplicationAbcConfig.java
-ApplicationConfig.java
-ApplicationFactory.java
-ApplicationXyzConfig.java
-Authentication.java
-Operations.java
-Payload.java
-RequestPayload.java
-ResponsePayload.java
-services
-YmlConfigurationSelection.java
-resources
-application.yml
-application-abc.yml
-application-xyz.yml
-MultipleYmlDemoProject.java
Content of application-abc.yml
authentication:
name: name
type: type
payload:
request:
- sequence: 1
attributes:
- attributes1
- attributes2
response:
- sequence: 1
attributes:
- attributes3
- attributes4
operations:
name: name
type: type
payload:
request:
- sequence: 1
attributes:
- attributes5
- attributes6
response:
- sequence: 1
attributes:
- attributes7
- attributes8
Content of application-xyz.yml
authentication:
name: name
type: type
payload:
request:
- sequence: 1
attributes:
- attributes9
- attributes10
response:
- sequence: 1
attributes:
- attributes11
- attributes12
operations:
name: name
type: type
payload:
request:
- sequence: 1
attributes:
- attributes13
- attributes14
response:
- sequence: 1
attributes:
- attributes15
- attributes16
Content of ApplicationConfig.java
public interface ApplicationConfig {
public Authentication getAuthentication();
public void setAuthentication(Authentication authentication);
public Operations getOperations();
public void setOperations(Operations operations);
}
Content of Authentication.java
public class Authentication {
private String name;
private String type;
private Payload payload;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Payload getPayload() {
return payload;
}
public void setPayload(Payload payload) {
this.payload = payload;
}
}
Content of Operations.java
public class Operations {
private String name;
private String type;
private Payload payload;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Payload getPayload() {
return payload;
}
public void setPayload(Payload payload) {
this.payload = payload;
}
}
Content of Payload.java
public class Payload {
private List<RequestPayload> request;
private List<ResponsePayload> response;
public List<RequestPayload> getRequest() {
return request;
}
public void setRequest(List<RequestPayload> request) {
this.request = request;
}
public List<ResponsePayload> getResponse() {
return response;
}
public void setResponse(List<ResponsePayload> response) {
this.response = response;
}
}
Content of RequestPayload.java
public class RequestPayload {
private String sequece;
private List<String> attributes;
public String getSequece() {
return sequece;
}
public void setSequece(String sequece) {
this.sequece = sequece;
}
public List<String> getAttributes() {
return attributes;
}
public void setAttributes(List<String> attributes) {
this.attributes = attributes;
}
}
Content of ResponsePayload.java
public class ResponsePayload {
private String sequece;
private List<String> attributes;
public String getSequece() {
return sequece;
}
public void setSequece(String sequece) {
this.sequece = sequece;
}
public List<String> getAttributes() {
return attributes;
}
public void setAttributes(List<String> attributes) {
this.attributes = attributes;
}
}
Content of ApplicationAbcConfig.java
#Configuration
#SpringBootConfiguration
#EnableConfigurationProperties
#org.springframework.context.annotation.PropertySource("classpath:application-abc.yml")
public class ApplicationAbcConfig implements ApplicationConfig, PropertySourceFactory {
private Authentication authentication;
private Operations operations;
#Override
public Authentication getAuthentication() {
return authentication;
}
#Override
public void setAuthentication(Authentication authentication) {
this.authentication = authentication;
}
#Override
public Operations getOperations() {
return operations;
}
#Override
public void setOperations(Operations operations) {
this.operations = operations;
}
#Override
public PropertySource<?> createPropertySource(#Nullable String name, EncodedResource resource) throws IOException {
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
String sourceName = name != null ? name : resource.getResource().getFilename();
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
} catch (IllegalStateException e) {
// for ignoreResourceNotFound
Throwable cause = e.getCause();
if (cause instanceof FileNotFoundException)
throw (FileNotFoundException) e.getCause();
throw e;
}
}
}
Content of ApplicationXyzConfig.java
#Configuration
#SpringBootConfiguration
#EnableConfigurationProperties
#org.springframework.context.annotation.PropertySource("classpath:application-xyz.yml")
public class ApplicationXyzConfig implements ApplicationConfig, PropertySourceFactory {
private Authentication authentication;
private Operations operations;
#Override
public Authentication getAuthentication() {
return authentication;
}
#Override
public void setAuthentication(Authentication authentication) {
this.authentication = authentication;
}
#Override
public Operations getOperations() {
return operations;
}
#Override
public void setOperations(Operations operations) {
this.operations = operations;
}
#Override
public PropertySource<?> createPropertySource(#Nullable String name, EncodedResource resource) throws IOException {
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
String sourceName = name != null ? name : resource.getResource().getFilename();
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
} catch (IllegalStateException e) {
// for ignoreResourceNotFound
Throwable cause = e.getCause();
if (cause instanceof FileNotFoundException)
throw (FileNotFoundException) e.getCause();
throw e;
}
}
}
Content of ApplicationFactory.java
#Component
public class ApplicationFactory {
#Autowired
private ApplicationAbcConfig applicationAbcConfig;
#Autowired
private ApplicationXyzConfig applicationXyzConfig;
public ApplicationConfig getApplicationPropertiesConfig(String application) {
if (application.equalsIgnoreCase("abc")) {
return applicationAbcConfig;
} else if (application.equalsIgnoreCase("xyz")) {
return applicationXyzConfig;
} else {
return null;
}
}
}
Content of YmlConfigurationSelection.java
public class YmlConfigurationSelection {
#Autowired
private ApplicationFactory applicationFactory;
private ApplicationConfig applicationConfig;
public Object accessingProperties(String application) {
applicationConfig = applicationFactory.getApplicationPropertiesConfig(application);
return null;
}
}
Content of MultipleYmlDemoProject.java
#SpringBootApplication
#SpringBootConfiguration
#PropertySource(factory = ApplicationAbcConfig.class, value = "classpath:application-abc.yml")
#PropertySource(factory = ApplicationXyzConfig.class, value = "classpath:application-xyz.yml")
public class MultipleYmlDemoProject {
public class MultipleYmlDemo {
public static void main(String[] args) {
ConfigurableApplicationContext ctx =
SpringApplication.run(YamlPropertysourceApplication.class, args);
ConfigurableEnvironment env = ctx.getEnvironment();
}
}
}
It looks like you have an old spring application that was attempted to be migrated to spring boot.
Spring boot works natively with yaml files, so if you do the integration in a spring boot way, it will be possible to delete a lot of boilerplate code that you have to maintain. Also the naming of configurations is problematic: the names application-<something>.yml are reserved to be used with spring boot profiles, maybe if you'll rename to myprops-abc/xyz.yaml it will behave in a different way, I can't say for sure.
All-in-all I suggest you the following way, which is much better IMO:
Both configuration sets must be loaded into one configuration, so create a configuration properties file that denotes this one configuration:
#ConfigurationProperties(prexix="security")
public class SecurityConfigProperties {
private SecurityRealm abc;
private SecurityRealm xyz;
// getters, setters
}
public class SecurityRealm {
private Authentication autentication;
private Operations operations;
// getters setters
}
public class Authentication {...}
private class Operations {...}
Now place all the content from abc and xyz yaml into one file application.yaml and give a 'security' prefix:
security:
abc: // note, this 'abc' matches the field name of the configuration
authentication:
...
operations:
....
xyz:
authentication:
...
operations:
....
OK, everything is mapped, create the configuration like this:
#Configuration
#EnableConfigurationProperties(SecurityConfigProperties.class)
public class SecurityConfiguration {
#Bean
public SecurityBeanForABC(SecurityConfigProperties config) {
return new SecurityBeanForABC(config.getAbc().getAuthentication(), config.getAbc().getOperations());
}
... the same for XYZ
}
Note that with this approach you only maintain a configuration mapping in java objects and there is no code for loading / resolving properties) - everything is done by spring boot automatically. If you configure a special annotation processor and have a descent IDE you can get even auto-completion facilities for those yaml properties but its out of scope for this question. The point is that doing things in a way directly supported by spring boot has many advantages :)

Jackson custom serializers

Can a single custom serializer be used as both key serializer and normal object serializer?
i.e. sometime use the serializer as a key serializer for serializing map keys while at other time serializing the object normally.
I was facing issues with JsonGenerator object passed to the serializer method.
When used as a key serializer it expects a field name but when using normally, it expects the value.
You can use the same custom serializer but you need to distinguish somehow whether you need to generate property or whole object. Map is serialized to JSON Object where Map keys are converted to JSON Object properties. To generate property with Jackson we need to use writeFieldName method. To distinguish how you would like to use this serialiser in constructor you can provide this information. Example:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.util.Collections;
public class JsonApp {
public static void main(String[] args) throws Exception {
SimpleModule userModule = new SimpleModule();
userModule.addSerializer(User.class, new UserJsonSerializer(false));
userModule.addKeySerializer(User.class, new UserJsonSerializer(true));
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.registerModule(userModule);
User user = new User();
System.out.println(mapper.writeValueAsString(Collections.singletonMap(user, user)));
}
}
class User {
private String firstName = "Tom";
private String lastName = "Smith";
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
class UserJsonSerializer extends JsonSerializer<User> {
private final boolean generateKey;
UserJsonSerializer(boolean generateKey) {
this.generateKey = generateKey;
}
#Override
public void serialize(User value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
if (generateKey) {
serializeAsMapKey(value, gen);
} else {
serializeAsObject(value, gen);
}
}
private void serializeAsMapKey(User value, JsonGenerator gen) throws IOException {
gen.writeFieldName(String.join(",", value.getFirstName(), value.getLastName()));
}
private void serializeAsObject(User value, JsonGenerator gen) throws IOException {
gen.writeStartObject();
gen.writeFieldName("first");
gen.writeString(value.getFirstName());
gen.writeFieldName("last");
gen.writeString(value.getLastName());
gen.writeEndObject();
}
}
Above code prints:
{
"Tom,Smith" : {
"first" : "Tom",
"last" : "Smith"
}
}
If you do not have any common logic you can just create two separate classes: UserJsonSerializer and UserKeyJsonSerializer which is an object oriented and clear solution.

Jackson ObjectMapper readValue() unrecognized field when parsing to Object

I am creating simple rest client in Java/Spring. My request has been consumed properly by remote service and I got the response String something:
{"access_token":"d1c9ae1b-bf21-4b87-89be-262f6","token_type":"bearer","expires_in":43199,"grant_type":"client_credentials"}
The code below is the Object where I want to bind values from Json Response
package Zadanie2.Zadanie2;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Token {
String access_token;
String token_type;
int expiresIn;
String grantType;
//////////////////////////////////////////////////////
public Token() {
/////////////////////////////////
}
/////////////////////////////////////////////////////
public void setAccessToken(String access_token) {
this.access_token=access_token;
}
public String getAccessToken() {
return access_token;
}
////////////////////////////////////////////////
public void setTokenType(String token_type) {
this.token_type=token_type;
}
public String getTokenType() {
return token_type;
}
//////////////////////////////////////////////////////
public void setExpiresIn(int expiresIn) {
this.expiresIn=expiresIn;
}
public int getExpiresIn() {
return expiresIn;
}
//////////////////////////////////////////////////////////
public void setGrantType(String grantType) {
this.grantType=grantType;
}
public String getGrantType() {
return grantType;
}
}
all the time I am getting "unrecognized field access_token" but when I add objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
then access_token will be null
jsonAnswer=template.postForObject(baseUriAuthorize, requestEntity, String.class);
System.out.println(jsonAnswer);
Token token=objectMapper.readValue(jsonAnswer, Token.class);
System.out.println(token.getAccessToken());
I tried with #JsonProperty annotations. I tried with changing field by for example "#JsonProperty(accessToken)" because I thought there is an issue with "_" sign in variable name. I added getters and setters. Maybe there is a problem with the version I use but I don't think so because I am using "com.fasterxml.jackson.core"
You tried with "#JsonProperty(accessToken)". But your json contains access_token. how it works?
Try with this class:
public class Token {
#JsonProperty("access_token")
String accessToken;
#JsonProperty("token_type")
String tokenType;
int expiresIn;
String grantType;
//getter setter
}
Your setters do not match with the JSON key.
To read it correctly, you should change your setters to:
setAccess_token()
setToken_type()
...
But honestly, this is so ugly.
Try following the Java bean name convention and customize the JSON key with #JsonProperty:
public class Token {
#JsonProperty("access_token")
String accessToken;
....
}

How to convert RequestHeader to custom object in Spring

I have method in my controller:
#RequestMapping(method = RequestMethod.POST)
public CustomObject createCustomObject(final #RequestHeader("userId") Long userId) {
...
}
Can I write some custom converter or something like that to convert this RequestHeader userId param to User object so my method will be:
#RequestMapping(method = RequestMethod.POST)
public CustomObject createCustomObject(final User user) {
...
}
Is it possible to do with spring-mvc?
Basically I implemented it with the suggestion from the comments.
Below is an example:
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
#RestController
public class SimpleController {
#GetMapping("/user")
public String greeting(#RequestHeader(name = "userId") User user) {
return "Hey, " + user.toString();
}
}
public class User {
private String id;
private String firstName;
private String lastName;
...
}
And then we'll create a converter:
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
#Component
public class UserFromHeaderConverter implements Converter<String, User> {
#Override
public User convert(final String userId) {
// fetch user from the database etc.
final User user = new User();
user.setId(userId);
user.setFirstName("First");
user.setLastName("Last");
return user;
}
}
To test it, please execute: curl --header "userId: 123" localhost:8080/user
Result would be: Hey, User{id='123', firstName='First', lastName='Last'}
Versions:
spring-boot:2.0.3
spring-web:5.0.7
if I understand you, you want to receive a parameter and convert it to a complex object.
You must define a custom DataBinder-process implementing PropertyEditorSupport and register this for a type.
For example, if you want to get a bd user form id create the class:
public class UserEditor extends PropertyEditorSupport {
private final UserDAO userDao;
public <T> CacheEditor(UserDAO userDao) {
this.userDao = userDao;
}
#Override
public void setAsText(String text) throws IllegalArgumentException {
if (text != null && !text.isEmpty()) {
Long code = Long.parseLong(text);
setValue(userDao.getById( code));
} else {
setValue(null);
}
}
...
}
and register editor:
#Controller
public class MyFormController {
#Autowire
private UserDAO userDao;
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(User.class, new UserEditor(userDao));
}
....
More info:
spring-framework reference webdatabinder
an example

Jackson JSON Processor: SerializationConfig.Feature.USE_ANNOTATIONS setted to false

Hi I'm facing with a nasty problem while using Jackson JSON PRocessor with ObjectMapper class.
This is my test class that should Serialize an Object (UserHeader) into a Json String.
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
public class TestJson {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
UserHeader userHeader = new UserHeader();
userHeader.setFirstName("A");
userHeader.setLastName("A1");
userHeader.setSystem("2A");
mapper.configure(SerializationConfig.Feature.USE_ANNOTATIONS, false);
StringWriter sw = new StringWriter();
mapper.writeValue(sw, userHeader);
System.out.println(sw.toString());
}
}
This is my UserHeader class with Annotations that are used from a different ObjectMapper (not this one)
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Typing;
#JsonSerialize(typing=Typing.STATIC)
public class UserHeader implements Serializable,LoggedObject, MessagesInterface {
private static final long serialVersionUID = 1L;
private String system;
private String userName;
private String firstName;
private String lastName;
private List<Scrivania> scrivanie;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
#JsonProperty("Nome utente")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#JsonProperty("Cognome utente")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#JsonProperty("Scrivanie associate")
public List<Scrivania> getScrivanie() {
return scrivanie;
}
public void setScrivanie(List<Scrivania> scrivanie) {
this.scrivanie = scrivanie;
}
#JsonProperty("Sistema (IAM o EDOC)")
public String getSystem() {
return system;
}
public void setSystem(String system) {
this.system = system;
}
#Override
#JsonIgnore
public String getObjectId() {
return this.userName;
}
#Override
#JsonIgnore
public Object getObjectData() {
try {
return this.clone();
}
catch (Exception e) {
return null;
}
}
#Override
public String getName() {
return this.userName;
}
}
However if I run the main method the system returns to me this exception:
Exception in thread "main" java.lang.NullPointerException
at org.codehaus.jackson.map.introspect.AnnotatedClass.resolveClassAnnotations(AnnotatedClass.java:295)
at org.codehaus.jackson.map.introspect.AnnotatedClass.construct(AnnotatedClass.java:141)
at org.codehaus.jackson.map.introspect.BasicClassIntrospector.forClassAnnotations(BasicClassIntrospector.java:185)
at org.codehaus.jackson.map.introspect.BasicClassIntrospector.forClassAnnotations(BasicClassIntrospector.java:15)
at org.codehaus.jackson.map.SerializationConfig.introspectClassAnnotations(SerializationConfig.java:661)
at org.codehaus.jackson.map.ser.BasicSerializerFactory.createTypeSerializer(BasicSerializerFactory.java:180)
at org.codehaus.jackson.map.ser.BeanSerializerFactory.findPropertyContentTypeSerializer(BeanSerializerFactory.java:406)
at org.codehaus.jackson.map.ser.BeanSerializerFactory._constructWriter(BeanSerializerFactory.java:778)
at org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:608)
at org.codehaus.jackson.map.ser.BeanSerializerFactory.constructBeanSerializer(BeanSerializerFactory.java:436)
at org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanSerializer(BeanSerializerFactory.java:349)
at org.codehaus.jackson.map.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:295)
at org.codehaus.jackson.map.ser.StdSerializerProvider._createUntypedSerializer(StdSerializerProvider.java:778)
at org.codehaus.jackson.map.ser.StdSerializerProvider._createAndCacheUntypedSerializer(StdSerializerProvider.java:731)
at org.codehaus.jackson.map.ser.StdSerializerProvider.findValueSerializer(StdSerializerProvider.java:369)
at http://stackoverflow.com/questions/6661717/how-to-process-an-invalid-value-with-jackson-json-processororg.codehaus.jackson.map.ser.StdSerializerProvider.findTypedValueSerializer(StdSerializerProvider.java:452)
at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:597)
at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:280)
at org.codehaus.jackson.map.ObjectMapper._configAndWriteValue(ObjectMapper.java:2260)
at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1813)
at it.unina.edoc.json.TestJson.main(TestJson.java:65)
I have no idea about this exception because #Annotations should be ignored due to USE_ANNOTATION false config.
Moreover if I set USE_ANNOTATION to true the error disappears.
I have these jars on my buildpath:
jackson-core-asl-1.8.3.jar
jackson-jaxrs-1.8.3.jar
jackson-mapper-asl-1.8.3.jar
jackson-xc-1.8.3.jar
The usage of the DeserializationConfig.Feature.USE_ANNOTATIONS property (set to false) will cause the JACKSON DeserializerConfig class to use a NopAnnotationIntrospector. Annotations of a class will then be resolved using this NopAnnotationIntrospector. The NopAnnotationIntrospector will return false on each isHandled request for any annotation on a class - and in fact will not use this annotation in further processing.
So - the system still "inspects" the annotations - which have to be on the Classpath in this case. As Android does not provide any jaxb-api annotations this leads to the NoClassDefFoundError.
I expected USE_ANNOTATIONS = false would bring JACKSON to totally ignore any annotations - but unfortunately it does not. I will now use the Jackson Streaming API to parse the JSON string instead of using JACKSON Data Binding capabilities.

Categories