私の解決策は、カスタムConditionalGenericConverter
に基づいています。それは@ModelAttribute
で動作します。実装全体を見てみましょう。
アプリケーションのブートストラップの例。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@SpringBootApplication
public class DemoApplication {
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Base64JsonToObjectConverter());
}
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
ここにカスタムアノテーションがあります。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Base64Encoded {
}
次に、コンバータの実装が必要です。ご覧のように、コンバータはString
- >Object
のみを変換します。ここで、Object
フィールドにはBase64Encoded
注釈を付ける必要があります。ここ
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Base64;
import java.util.Collections;
import java.util.Set;
@Component
public class Base64JsonToObjectConverter implements ConditionalGenericConverter {
private final ObjectMapper objectMapper;
private final Base64.Decoder decoder;
public Base64JsonToObjectConverter() {
this.objectMapper = new ObjectMapper();
this.decoder = Base64.getDecoder();
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return targetType.hasAnnotation(Base64Encoded.class);
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Object.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
String string = (String) source;
try {
byte[] decodedValue = this.decoder.decode(string);
return this.objectMapper.readValue(decodedValue, targetType.getType());
} catch (IllegalArgumentException | IOException e) {
throw new ConversionFailedException(sourceType, targetType, source, e);
}
}
}
POJOの例(注釈付きフィールドを参照)、RESTコントローラです。
import com.example.demo.Base64Encoded;
public class MyRequest {
private String varA;
@Base64Encoded
private B varB;
public String getVarA() {
return varA;
}
public void setVarA(String varA) {
this.varA = varA;
}
public B getVarB() {
return varB;
}
public void setVarB(B varB) {
this.varB = varB;
}
}
import com.example.demo.domain.MyRequest;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@RequestMapping(path = "/test", method = RequestMethod.POST)
public MyRequest test(@ModelAttribute MyRequest myRequest) {
return myRequest;
}
}