Exemple JSON (notez que la chaîne a des espaces de fin):
{ "aNumber": 0, "aString": "string " }
Idéalement, l'instance désérialisée aurait une propriété aString avec une valeur de "string" (c'est-à-dire sans espaces de fin). Cela semble être quelque chose qui est probablement pris en charge mais je ne le trouve pas (par exemple dans DeserializationConfig.Feature).
Nous utilisons Spring MVC 3.x, donc une solution basée sur Spring conviendrait également.
J'ai essayé de configurer WebDataBinder de Spring sur la base d'une suggestion dans un post sur le forum mais cela ne semble pas fonctionner lors de l'utilisation d'un convertisseur de message Jackson:
@InitBinder
public void initBinder( WebDataBinder binder )
{
binder.registerCustomEditor( String.class, new StringTrimmerEditor( " \t\r\n\f", true ) );
}
Avec un désérialiseur personnalisé , vous pouvez effectuer les opérations suivantes:
<your bean>
@JsonDeserialize(using=WhiteSpaceRemovalSerializer.class)
public void setAString(String aString) {
// body
}
<somewhere>
public class WhiteSpaceRemovalDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jp, DeserializationContext ctxt) {
// This is where you can deserialize your value the way you want.
// Don't know if the following expression is correct, this is just an idea.
return jp.getCurrentToken().asText().trim();
}
}
Cette solution implique que cet attribut de bean sera toujours sérialisé de cette façon, et vous devrez annoter chaque attribut que vous souhaitez désérialiser de cette façon.
Solution facile pour les utilisateurs de Spring Boot, ajoutez simplement l'extension SimpleModule de walv à votre contexte d'application:
package com.example;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.stereotype.Component;
import Java.io.IOException;
@Component
public class StringTrimModule extends SimpleModule {
public StringTrimModule() {
addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException,
JsonProcessingException {
return jsonParser.getValueAsString().trim();
}
});
}
}
Une autre façon de personnaliser Jackson consiste à ajouter des beans de type com.fasterxml.jackson.databind.Module à votre contexte. Ils seront enregistrés avec chaque bean de type ObjectMapper, fournissant un mécanisme global de contribution de modules personnalisés lorsque vous ajoutez de nouvelles fonctionnalités à votre application.
si vous n'utilisez pas Spring Boot, vous devez enregistrer le StringTrimModule vous-même (vous n'avez pas besoin de l'annoter avec @Component)
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="modulesToInstall" value="com.example.StringTrimModule"/>
</bean
Le problème de l'annotation @JsonDeserialize est que vous devez toujours vous rappeler de la mettre sur le setter. Pour le faire globalement "une fois pour toutes" avec Spring MVC, j'ai fait les étapes suivantes:
pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>
Créez un ObjectMapper personnalisé:
package com.mycompany;
import Java.io.IOException;
import org.Apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class MyObjectMapper extends ObjectMapper {
public MyObjectMapper() {
registerModule(new MyModule());
}
}
class MyModule extends SimpleModule {
public MyModule() {
addDeserializer(String.class, new StdScalarDeserializer<String> (String.class) {
@Override
public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
return StringUtils.trim(jp.getValueAsString());
}
});
}
}
Mettez à jour le servlet-context.xml de Spring:
<bean id="objectMapper" class="com.mycompany.MyObjectMapper" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Pour Spring Boot, il suffit de créer un désérialiseur personnalisé comme documenté dans le manuel .
Ce qui suit est mon code Groovy mais n'hésitez pas à l'adapter pour qu'il fonctionne en Java.
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import org.springframework.boot.jackson.JsonComponent
import static com.fasterxml.jackson.core.JsonToken.VALUE_STRING
@JsonComponent
class TrimmingJsonDeserializer extends JsonDeserializer<String> {
@Override
String deserialize(JsonParser parser, DeserializationContext context) {
parser.hasToken(VALUE_STRING) ? parser.text?.trim() : null
}
}
com.fasterxml.jackson.dataformat
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.5.3</version>
</dependency>
CsvUtil.Java
CsvSchema bootstrapSchema = CsvSchema.emptySchema().withHeader().sortedBy();
CsvMapper mapper = new CsvMapper();
mapper.enable(CsvParser.Feature.TRIM_SPACES);
InputStream inputStream = ResourceUtils.getURL(fileName).openStream();
MappingIterator<T> readValues =
mapper.readerFor(type).with(bootstrapSchema).readValues(inputStream);
Je pense qu'il est préférable d'étendre StringDeserializer par défaut car il gère déjà certains cas spécifiques (voir ici et ici ) qui peuvent être utilisés par des bibliothèques tierces. Vous trouverez ci-dessous la configuration de Spring Boot.
@JsonComponent
public class StringDeserializer extends com.fasterxml.jackson.databind.deser.std.StringDeserializer {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = super.deserialize(p, ctxt);
return value != null ? value.trim() : null;
}
}