Search code examples
javajacksonthymeleaf

Is there any way to add an ExclusionStrategy to Thymeleaf 3.0.5?


Now that Thyemleaf 3.0.5 is using Jackson, is there any way to add something like com.google.gson.ExclusionStrategy into the mix?

Also related to this:

Thymeleaf inline javascript ignore null

UPDATE:

Using the answer suggested by Metroids I was able to get this to work. I first had to switch from my XML config file to using a java config file for configuring Thymeleaf. Then I was able to get access to the StandardDialect as shown by Metroids. I implemented IStandardJavaScriptSerializer interface overriding #serializeValue(Object object, Writer writer).

IStandardJavaScriptSerializer implementation snippet...

@Override
public void serializeValue(Object object, Writer writer) {
    try {
        ExclusionStrategy exclusionStrategy = new MyApiJsonExcludeExclusionStrategy();
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setExclusionStrategies(exclusionStrategy);
    Gson gson = gsonBuilder.create();
    writer.write(gson.toJson(object));
    } catch (IOException e) {
        throw new TemplateProcessingException("An exception was raised while trying to serialize object to JavaScript using Gson", e);
    }
}

Thymeleaf Java Config snippet...

@Bean
public TemplateEngine templateEngine() {
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.setEnableSpringELCompiler(true);

    Set<IDialect> dialects = engine.getDialects();
    StandardDialect dialect = (StandardDialect) dialects.stream()
            .filter(d -> d instanceof StandardDialect)
            .findFirst()
            .get();
    dialect.setJavaScriptSerializer(new MyThymeleafJavascriptSerializer());

    engine.setTemplateResolvers(getTemplateResolvers());
    engine.setAdditionalDialects(getAdditionalDialects());
    return engine;
}

Solution

  • Yes, it's possible... but it's still kind of ugly to do in my opinion (since there is no easy way to get to the ObjectMapper without creating one yourself). I accomplished it by doing this... First, wherever you configure your template engine, you should be able to get access to the StandardDialect.

        Set<IDialect> dialects = templateEngine.getDialects();
        StandardDialect dialect = (StandardDialect) dialects.stream()
                .filter(d -> d instanceof StandardDialect)
                .findFirst()
                .get();
    

    From there you can create your own IStandardJavaScriptSerializer in which you can configure the ObjectMapper however you desire. (I created a SpecialJacksonSerializer with this line of code this.mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); to verify it worked.)

    dialect.setJavaScriptSerializer(new SpecialJacksonSerializer());
    

    Since thymeleaf is doing a lot of configuration in the background (see this file), you end up copying a lot of that code when creating your own. It would be nice if you could call dialect.getJavaScriptSerializer().getObjectMapper() or something like that, but it doesn't look like it's possible.