A story when building an application with a Spring Boot (Freemarker + Doma2) configuration.
It's bad to implement it with a loose understanding, but when I defined a session-scoped bean, I couldn't access properties like hoge.fuga
on ftl.
I should have accessed it via Getter like hoge.getFuga ()
, but I thought I should investigate the cause and make it possible to access the property, and I could do it.
By the way, when I returned it as JSON, it had strange properties, so I tried not to use it.
The session-scoped bean was wrapped in a proxy made with cglib
.
Perhaps this proxy has a ThreadLocal
variable and is a proxy for a different object for each request.
Just write a Configuration that strips the proxy on output to handle raw objects.
Fortunately, the proxy seems to have an interface called ScopedObject
, which I could strip with ScopedObject # getTargetObject
.
Click here for support for Freemarker
FreemarkerConfig.java
@Configuration
public class FreemarkerConfig {
@Autowired
void configureFreemarkerConfigurer(FreeMarkerConfig config) {
freemarker.template.Configuration templateConfig = config.getConfiguration();
templateConfig.setObjectWrapper(new CustomWrapper());
}
private static class CustomWrapper extends DefaultObjectWrapper {
CustomWrapper() {
super(freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
}
@Override
protected TemplateModel handleUnknownType(Object obj) throws TemplateModelException {
if (obj instanceof ScopedObject) {
return super.handleUnknownType(((ScopedObject) obj).getTargetObject());
}
return super.handleUnknownType(obj);
}
}
}
Click here for Jackson support
JacksonConfig.java
@Configuration
public class JacksonConfig {
@Autowired
public void configureObjectMapperConfig(ObjectMapper objectMapper) {
objectMapper.registerModule(new ScopedObjectModule());
}
private static class ScopedObjectModule extends Module {
@Getter
private final String moduleName = "scopedObjectModule";
@Override
public Version version() {
return PackageVersion.VERSION;
}
@Override
public void setupModule(SetupContext context) {
context.addSerializers(new Serializers.Base() {
@Override
public JsonSerializer<?> findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc) {
Class<?> raw = type.getRawClass();
if (ScopedObject.class.isAssignableFrom(raw)) {
return new ScopedObjectSerializer(type.getSuperClass());
}
return super.findSerializer(config, type, beanDesc);
}
});
}
}
@AllArgsConstructor
private static class ScopedObjectSerializer extends JsonSerializer<ScopedObject> {
private JavaType type;
@Override
public void serialize(ScopedObject value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
serializers.findValueSerializer(type).serialize(value.getTargetObject(), gen, serializers);
}
}
}
Recommended Posts