Fasterxml Jackson primitive boolean serialization - java

I'm using Fasterxml Jackson 2.2.2
I have a simple pojo with a boolean (primitive) attribute. When the default BeanSerializer and BeanPropertyWritter try to serialize it, this attribute is skipped when its value is false.
I want:
{"id":1, "enabled":false}
What I get is:
{"id":1}
The code in BeanPropertyWritter is:
// and then see if we must suppress certain values (default, empty)
if (_suppressableValue != null) {
if (MARKER_FOR_EMPTY == _suppressableValue) {
if (ser.isEmpty(value)) {
return;
}
} else if (_suppressableValue.equals(value)) {
return;
}
}
I've debugged it and found that BeanPropertyWritter._suppressableValue equals Boolean(false), so when a false boolean arrives to this block, it just returns and no output is returned.
What are my options? Can I configure the attribute's writter to un-set its _suppressableValue? What would be the easiest and simpler solution?

As was suggested, your ObjectMapper settings are probably non-default, and specify inclusion strategy of NON_DEFAULT.
But you can add #JsonInclude to override this either on your POJO class, or even for boolean property itself: make sure to use Inclusion.ALWAYS.

Related

Inconsistent Jackson "Unrecognized field" due to capitalization

Jackson seems to have a problem when the second letter of a field name is capitalized.
Take a map of values:
aaBoolean, true // works
aBoolean, false // fails
anInt, 0 // works
aString, "a" // fails
I used Jackson's ObjectMapper.convertValue(map) to create a Java object. Here's a snippet of Java code:
private boolean aaBoolean; // GOOD
public boolean getAaBoolean() { return aaBoolean; }
public void setAaBoolean(boolean value) { this.aaBoolean=value;}
private boolean aBoolean; // FAILS!!! Jackson "Unrecognized field"
public boolean getABoolean() { return aBoolean; }
public void setABoolean(boolean value) { this.aBoolean=value;}
I get an error message with all 18 fields. Note the camel case fails when the capital is the second letter:
Unrecognized field "aBoolean" (class Test), not marked as ignorable
(18 known properties: "anInt", "anullableBoolean", "aboolean", "aaBoolean",
"lastModifiedDate", "adate", "anullableDate", "astring", "anullableString",
"createdDate", "anullableFloat", "id", "along", "anullableLong", "createdBy",
"anullableInt", "lastModifiedBy", "afloat"])
If I change aBoolean to aaBoolean, that passes and Jackson fails on aString.
Per other Stack Overflow posts, I've verified that the field name and getter/setter match (aBoolean is getABoolean() and aaBoolean is getAaBoolean()).
If it matters, here's how the ObjectMapper was created:
ObjectMapper mapper = new ObjectMapper();
mapper.setTimeZone(TimeZone.getTimeZone("CST"));
I can post the full code but I think the above is enough.
I can modify my variable names to get around this, but now I'm curious - is this a bug or am I missing something about how Jackson handles name conversion?
It looks like the default Jackson behavior through v2.9 is to lowercase any leading upper case getter/setter methods. So "getURLtoServer" becomes "urltoServer".
Jackson source code executing this here:
https://github.com/FasterXML/jackson-databind/blob/2.9/src/main/java/com/fasterxml/jackson/databind/util/BeanUtil.java#L246
However, the JavaBean spec says to not change any casing if the first two characters are uppercase. So the JavaBean of "getURLtoServer" would be "URLtoServer".
Jackson introduced MapperFeature.USE_STD_BEAN_NAMING as an option to enforce this part of the JavaBean spec. However, it looks like that's being removed in v3.x when it becomes the default behavior:
https://github.com/FasterXML/jackson-databind/issues/1772
So for your case, it looks like you can either have the JSON string "aboolean" without using USE_STD_BEAN_NAMING, or else you can have the JSON string "ABoolean" with using USE_STD_BEAN_NAMING.
The other option is to manually specify what you want:
#JsonProperty("aBoolean")
public boolean getABoolean() { return aBoolean; }

Apache Commons Configuration validate properties file

I am using Apache Commons Configuration library with PropertiesConfiguration.
My application loads the config file right after its started, like this:
public PropertiesConfiguration loadConfigFile(File configFile) throws ConfigurationNotFoundException {
try {
if (configFile != null && configFile.exists()) {
config.load(configFile);
config.setListDelimiter(';');
config.setAutoSave(true);
config.setReloadingStrategy(new FileChangedReloadingStrategy());
setConfigLoaded(true);
}
else {
throw new ConfigurationNotFoundException("Configuration file not found.");
}
} catch (ConfigurationException e) {
logger.warn(e.getMessage());
setDefaultConfigValues(config);
config.setFile(configFile);
}
return config;
}
My question is, how can I validate the configFile, so I can be sure that no property in that file is missing and later in my code I won't get a NullPointerException when trying to access the properties, e.g.:
PropertiesConfiguration config = loadConfig(configFile);
String rootDir = config.getString("paths.download"); // I want to be sure that this property exists right at the app start
I didn't found anything in the documentation or google, just something about XML validation.
The goal is to provide feedback to the user at program start that the configuration file is corrupted.
There is no build-in mechanism for properties-file?
What is a configuration object supposed to do if you pass in a key to one of its get methods that does not map to an existing property?
the default behavior as implemented in AbstractConfiguration is to return null if the return value is an object type.
For primitive types as return values returning null (or any other special value) is not possible, so in this case a NoSuchElementException is thrown
// This will return null if no property with key "NonExistingProperty" exists
String strValue = config.getString("NonExistingProperty");
// This will throw a NoSuchElementException exception if no property with
// key "NonExistingProperty" exists
long longValue = config.getLong("NonExistingProperty");
For object types like String, BigDecimal, or BigInteger this default behavior can be changed:
If the setThrowExceptionOnMissing() method is called with an argument of true, these methods will behave like their primitive counter parts and also throw an exception if the passed in property key cannot be resolved.
Situation is little tricky for Collection & array types as they will return empty collection or array.

Deserialise Json to class with Generic fields

I currently have the following class
public class Setting<T> {
private T value;
private T defaultValue;
/* getters and setters */
}
The trouble I'm having is deserializing from the Json, for example, having a Setting will work fine if the Json is
{ \"value\": true, \"defaultValue\": false }
.. but, it will also accept
{ \"value\": \"true\", \"defaultValue\": \"false\" }
Even tho the field is of Setting. From what I understand, Java strips away all the generic info, so jackson cannot look it up at runtime. I have tried the following
Field currentSettingField = currentSettingsObject.getClass().getDeclaredField("mySetting");
if (currentSettingField != null) {
JavaType settingType = mapper.getTypeFactory().constructType(settingField.getGenericType(), Setting.class);
Setting setting = objectMapper.readValue(currentSettingNode.toString(), settingType);
}
Which has been somewhat successful, however I can still do things like converting a String or Integer value from Json to a type of Setting. Am I doing something wrong here, or would I be better just have a simple marker interface, then derive each type of setting I want from it?
From what I see from Jackson's code, it tries it's best to guess the value for the boolean and matches strings:
// And finally, let's allow Strings to be converted too
if (t == JsonToken.VALUE_STRING) {
String text = jp.getText().trim();
if ("true".equals(text)) {
return Boolean.TRUE;
}
if ("false".equals(text)) {
return Boolean.FALSE;
}
if (text.length() == 0) {
return (Boolean) getEmptyValue();
}
throw ctxt.weirdStringException(text, _valueClass, "only \"true\" or \"false\" recognized");
}
So if you change you generic type to Integer or provide an incorrect input i.e. 'tru', it won't able to match it.
"Java strips away all the generic info"
AFAIK, Java can do this, but it doesn't remove type attributes information from classes. It doesn't use them however during runtime. This make possible for libraries like Jackson are able to use it.

How to authenticate against a collection of domain objects in Spring Expression Language SpEL

My principle is an instance of 'foo' that has a collection of 'bars'. Each 'bar' has an id that I want to match with the 'id' passed as the resource requested. Can I do something like the following in Spring SpEL? And if so, how?
Example (psuedo syntax; cause I don't know the correct way which is why I am here)
#PreAuthorize("principal.transactions.contains(instance where dto.transactionId == instance.id")")
public SomeResponse processTransaction(RequestDto dto) {
...
}
Essentially the equivalent of this
for(Transaction t : principal.transactions){
if(t.getId() == dto.getTransactionId())
return true;
}
return false;
I am not sure that it is possible to do in plain SpEL. But you can try a workaround:
#PreAuthorize("principal.hasTransactionId(#dto.transactionId)")
Then you need to add hasTransactionId(Integer transactionId) method to your principal. This method must return a boolean value.

Set default value in JAXB

I have an xml file as following and when the filePath2 is null or empty I want the value of that to be of filePath1's value. Is there a way in which I can achieve this through JAXB.
<file filePath1="C:/filePath">
<subFile name="Test">
<filePath2></filePath2>
</subFile>
<file/>
I don't want to hardcode the default value. If the value for filePath2 is null or blank("") I want to set the filePath1 attribute as the value of 'String filePath'. Is there a way to do it via a setter in JAXB?
Using plain Oracle JAXB I only see the possibility to implement that using an javax.xml.bind.Unmarshaller.Listener.
Implement that interface in your model class and perform the necessary checks in the afterUnmarshal(..) method.
There you can access the value of filePath1 and set (if necessary) it to filePath2.
Thanks for all your inputs, at the end I opted for a simpler solution; to update the setter where filePath2 is being called.
The JAXB part -
String filePath2;
#XmlElement(required = true)
public void setFilePath2(final String file) {
this.filePath2= file;
}
Where filePath is used -
if (filePath2 == null || filePath2.isEmpty()) {
setFilePath2(getFilePath1());
}
If you come across a bettr yet simple solution let me know.
If you can use annotations, than this should do the trick
...
private String foo;
#XmlElement(defaultValue="bar")
public String getFoo() {
return foo;
}
...

Categories