Jackson Overcoming Underscores in Favor of Camel-Case

Jackson overcoming underscores in favor of camel-case

You should use the @JsonProperty on the field you want to change the default name mapping.

class User{
@JsonProperty("first_name")
protected String firstName;
protected String getFirstName(){return firstName;}
}

For more info: the API

Deserialising JSON with underscores to camel case in Java using Jackson?

Well, you can have an implementation for PropertyNamingStrategy that looks something like this:

import org.codehaus.jackson.map.MapperConfig;
import org.codehaus.jackson.map.PropertyNamingStrategy;
import org.codehaus.jackson.map.introspect.AnnotatedField;
import org.codehaus.jackson.map.introspect.AnnotatedMethod;

public class CustomNameStrategy extends PropertyNamingStrategy {
@Override
public String nameForField(MapperConfig config, AnnotatedField field, String defaultName) {
return convert(defaultName);
}

@Override
public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) {
return convert(defaultName);
}

@Override
public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) {
return convert(defaultName);
}

public String convert(String defaultName) {
char[] arr = defaultName.toCharArray();
StringBuilder nameToReturn = new StringBuilder();

for (int i = 0; i < arr.length; i++) {
if (arr[i] == '_') {
nameToReturn.append(Character.toUpperCase(arr[i + 1]));
i++;
} else {
nameToReturn.append(arr[i]);
}
}
return nameToReturn.toString();
}
}

then in your implementation or the class that does the desrialization you can have:

ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new CustomNameStrategy());
YourClass yourClass = mapper.readValue(yourJsonString, YourClass.class);

Not able to convert underscore case to camel case with Jackson

Always respect the Java naming conventions in your Java code. Use annotations to deal with Json not respecting them.

In this case, use JsonAlias

Annotation that can be used to define one or more alternative names for a property, accepted during deserialization as alternative to the official name

public class WPPostResponse {
@JsonAlias("featured_media")
Long featuredMedia;

public Long getFeaturedMedia() {
return featuredMedia;
}

public void setFeaturedMedia(Long featuredMedia) {
this.featuredMedia = featuredMedia;
}
}

Stop Jackson from changing case of variable names

The problem here is more about JavaBeans(TM) Specification. According to the spec (page 58)

However to support the occasional use of all upper-case names, we
check if the first two characters of the name are both upper case and
if so leave it alone

“FooBah” becomes “fooBah”

“Z” becomes “z”

“URL” becomes “URL”

And you have an edge case with aName field . Because if the getter looks like AName() , then when you convert back from this getter you should look for AName field according to the specification. Here is additional info explanation

So to fix this, you can use a proper getter(getaName()) or @JsonProperty("aName") annotation above field/getter

Here is similar question

Why does Jackson 2 not recognize the first capital letter if the leading camel case word is only a single letter long?

The problem you are seeing is due to the fact that Jackson uses Java Bean naming conventions to figure out the the Json properties in a Java class.

Here is a reference of the specific problem you see, the recommendation is not to capitalize either of the first two letters in your field. If you use an IDE like IntelliJ or eclipse and let the IDE generate the setters for you, you will notice the same "behavior" occurs, you will end up with the following methods:

public void setaLogId(String aLogId) {
this.aLogId = aLogId;
}

public String getaLogId() {
return aLogId;
}

Hence, when you change the "L" to lower case Jackson was able to figure it out the field you wanted to map.

Having said the above, you still have the alternative to use the "aLogId" field name and make Jackson work all you have to do is use the @JsonProperty annotation with the aLogId in it.

@JsonProperty("aLogId")
private String aLogId;

The following test code is to show how this will work:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {

@JsonProperty("aLogId")
private String aLogId;

public void setaLogId(String aLogId) {
this.aLogId = aLogId;
}

public String getaLogId() {
return aLogId;
}

public static void main(String[] args) {

ObjectMapper objectMapper = new ObjectMapper();

Test test = new Test();

test.setaLogId("anId");

try {
System.out.println("Serialization test: " + objectMapper.writeValueAsString(test));

String json = "{\"aLogId\":\"anotherId\"}";

Test anotherTest = objectMapper.readValue(json, Test.class);

System.out.println("Deserialization test: " +anotherTest.getaLogId());

} catch (Exception e) {
e.printStackTrace();
}

}
}

The output of the test is:

Serialization test: {"aLogId":"anId"}

Deserialization test: anotherId

How to convert camel case to lower case with underscores in a REST API?

If you want to make this behaviour the default one, you have to configure this in the object mapper that is responsible for serialization/deserialization of objects to json.
In Quarkus, you can use either Jackson or JsonB for object mapping.

For Jackson, you can control the behaviour of field names using PropertyNamingStrategy which you want to set to SNAKE_CASE. To set this globally, create an ObjectMapperCustomizer like so:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import io.quarkus.jackson.ObjectMapperCustomizer;

import javax.inject.Singleton;

@Singleton
public class ObjectMapperConfig implements ObjectMapperCustomizer {

@Override
public void customize(ObjectMapper objectMapper) {
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
}
}

You can control many more aspects of serialization e.g. ignore unknown props during deserialization, date formatting, etc.

You need to have a dep to quarkus-resteasy-jackson:

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>

If you want to use JsonB (quarkus-resteasy-jsonb) then you can try it with the following JsonbConfigCustomizer

import io.quarkus.jsonb.JsonbConfigCustomizer;

import javax.inject.Singleton;
import javax.json.bind.JsonbConfig;
import javax.json.bind.config.PropertyNamingStrategy;
@Singleton
public class JsonBCustomizer implements JsonbConfigCustomizer {

public void customize(JsonbConfig config) {
config.withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES);
}
}

Set naming strategy to lower camel case for one class

To enforce lowerCamelCase, you can use the annotation

@JsonNaming(PropertyNamingStrategy::class)

This enforces the default naming strategy (lowerCamelCase) and overrides a globally configured naming strategy.

Jersey JSON switching from camel case to underscores (snake case)

This is something that needs to be configured with the Jackson ObjectMapper. You can do this in a ContextResolver. Basically, you need something like

@Provider
public class MapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper mapper;

public MapperProvider() {
mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
}

@Override
public ObjectMapper getContext(Class<?> cls) {
return mapper;
}
}

Then register with your client

client.register(MapperProvider.class);

If you need this support on the server also, then you will need to register it on the server too.



Related Topics



Leave a reply



Submit