3

I'm trying to get my Formatter for my model running. The model contains an annotation like the following code. I have multiple Formatter i don't get running yet, but can't figure out the issue.

public class Customer {
    @Trim
    private String firstName;
    //some other properties, getter and setter
}

The annotation is correctly set, as far as i know:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface Trim {
    boolean squashMultipleSpaces() default true;
}

And the AnnotationFormatterFactory

public class TrimAnnotationFormatterFactory implements AnnotationFormatterFactory<Trim> {
    public TrimAnnotationFormatterFactory() {
    }

    public Set<Class<?>> getFieldTypes() {
        return Collections.singleton(String.class);
    }

    public Printer<String> getPrinter(Trim annotation, Class<?> fieldType) {
        return new TrimAnnotationFormatterFactory.TrimFormatter(annotation.squashMultipleSpaces());
    }

    public Parser<String> getParser(Trim annotation, Class<?> fieldType) {
        return new TrimAnnotationFormatterFactory.TrimFormatter(annotation.squashMultipleSpaces());
    }

    private static class TrimFormatter implements Formatter<String> {
        private final boolean squashMultipleSpaces;

        TrimFormatter(boolean squashMultipleSpaces) {
            this.squashMultipleSpaces = squashMultipleSpaces;
        }

        public String parse(String text, Locale locale) {
            return this.process(text);
        }

        public String print(String object, Locale locale) {
            return this.process(object);
        }

        private String process(String text) {
            if (text == null) {
                return null;
            } else {
                return this.squashMultipleSpaces ? text.trim().replaceAll("\\s+", " ") : text.trim();
            }
        }
    }
}

I added my custom AnnotationFormatterFactory to the FormatterRegistry. When I'm dbuggign it, i can see that it is added to the FormatterRegistry successfully.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatterForFieldAnnotation(new TrimAnnotationFormatterFactory());
    }
}

And the controller looks like:

@Controller
public class CustomerController {

    @PostMapping(value = "/customer")
    @ResponseBody
    public Customer saveCustomer(@RequestBody Customer customer) {
        return customer;
    }
}

if my input looks like this

"       Christian     Walter"

in the controller the model is still the same. I was expecting

"Christian Walter"

in my model.

Why doesn't my formatter work? Or do i have to use PropertyEditor and if so, how could i use it with annotations?

UPDATE: The formatter is successfully registered, but isn't called. And added the controller.

Thanks for your help.

Manuel
  • 1,928
  • 2
  • 16
  • 26

1 Answers1

1

From your last update, i understand that you're using json to deserialize your object. In this case you have to (in my opinion) write your own deserializer, as :

public class WhiteSpaceTrimmerDeserializer extends JsonDeserializer<String> {
    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        JsonNode node = jp.getCodec().readTree(jp);
        return node.asText().replaceAll("\\s+", " ").trim();
    }
}

And use it like :

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class Customer {

    private String firstName;


    public String getFirstName() {
        return firstName;
    }

    @JsonDeserialize(using = WhiteSpaceTrimmerDeserializer.class)
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}

So " Christian Walter" will produce "Christian Walter".

There's another ways to configure this deserializer, you can look at : Can Jackson be configured to trim leading/trailing whitespace from all string properties?

But why Formatter is not working ? The only explanation i have is that @RequestBody/@ResponseBody are not handled by the WebMvcConfigurer.

bubbles
  • 2,597
  • 1
  • 15
  • 40
  • No. This is not the issue. It should squash all spaces to one. The issue is, that the formatter doesn't get called. They are successfully registered, but not called. – Manuel Jul 09 '19 at 19:22
  • i put your code here https://github.com/mcherb/gs-serving-web-content/tree/master/complete and it works fine ! have we the same configuration ? can you share your code on github ? – bubbles Jul 09 '19 at 21:36
  • I see that your controller is working. That's interesting. When i'm updating your code to my needs, then it's not working anymore. i thought formatter also works if i use the controller, like in my updated question. Take a look at my controller. The output is still unformatted. – Manuel Jul 10 '19 at 10:03
  • Could you add your html template ? – bubbles Jul 10 '19 at 10:08
  • There is no template. It's just rest. Consuming and producing json – Manuel Jul 10 '19 at 13:38
  • @ManuelPolacek i've updated my answer according to your last informations – bubbles Jul 10 '19 at 19:08
  • I tried to run it with the json deserialize serialize annotation, but it's not working yet. I think you're right with the request and response body. Looks like different behaviour. I'm gonna do some tests today and let you know, if the implementation worked today, or not. Thanks in advance. – Manuel Jul 11 '19 at 06:10
  • you welcome, i already tested it before putting it, i can update my github project if you want to – bubbles Jul 11 '19 at 14:54