java


Overcome “Can not construct instance of InterfaceClass” without hinting the parent


I have this method in my controller:
#RequestMapping(method = RequestMethod.POST)
InterfaceClass insert(#RequestBody InterfaceClass interfaceClass) {
// Do something
}
The error I am getting is pretty straightforward and self-explanatory:
Can not construct instance of InterfaceClass: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information.
Basically, I need to tell Spring that I have a concrete implementation of InterfaceClass, ClassImpl.
I tried:
#JsonRootName("InterfaceClass")
public class ClassImpl implements InterfaceClass {
}
to no extent. I cannot use #JsonTypeInfo as the parent interface class InterfaceClass should not be aware of ClassImpl and they are in different modules. What I have also tried:
Implement InterfaceClass with abstract AbstractClass and put:
#JsonDeserialize(as = AbstractClass.class)
on top of InterfaceClass. Then extend AbstractClass with ClassImpl. The error simply becomes:
Can not construct instance of InterfaceClass: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information.
Further tried:
public class ControllerClass<E extends InterfaceClass> {
#RequestMapping(method = RequestMethod.POST)
InterfaceClass insert(#RequestBody E interfaceClass) {
InterfaceClass object = (InterfaceClass) interfaceClass;
}
}
and this results in:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to InterfaceClass
as expected.
I was really expecting Spring Boot to handle component discovery since there is only one concrete implementation of InterfaceClass or AbstractClass, which is ClassImpl in my classpath. Maybe I am doing something wrong? How can I overcome this, without explicitly hinting the InterfaceClass on where its implementation is (e.g. no #JsonDeserialize, etc.)?
Solution 1 - Dynamically register subtypes
You can define the subtypes dynamically.
1. On the interface, define a JSON field (#type) to be used as identifier:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "#type")
public interface InterfaceClass {
}
2. Add "#type" field to your JSON payload
{
...
"#type": "someName"
}
2. Register the inteface's subtypes dynamically:
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() {
public void configure(ObjectMapper objectMapper) {
objectMapper.registerSubtypes(ClassImpl.class);
super.configure(objectMapper);
};
};
return builder;
}
4. Specify the "#type" name on your concrete class (optional):
//Optional, otherwise uses the Simple class name (ie: 'ClassImpl')
#JsonTypeName("someName")
public class ClassImpl implements InterfaceClass {
}
5. Use can now use the interface with #RequestBody:
#RequestMapping(method = RequestMethod.POST)
InterfaceClass insert(#RequestBody InterfaceClass interfaceClass) {
}
Solution 2 - Dynamically register a custom Deserializer
If adding a #type field isn't possible (or not wanted), you may also define a Custom Deserializer for your interface, which would in fact create a ClassImpl:
1. Define a custom deserializer:
class ClassImplJsonDeserializer extends JsonDeserializer<ClassImpl> {
#Override
public ClassImpl deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return jp.readValuesAs(ClassImpl.class).next();
}
}
2. Dynamically set the custom deserializer:
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.deserializerByType(InterfaceClass.class, new ClassImplJsonDeserializer());
return builder;
}
3. Remove #JsonTypeInfo from the interface:
public interface InterfaceClass {
}

Related Links

JAXB bindings of complex type to new classname
How to download a file with Retrofit2?
Context aware recommendation engine
No Such Definition Exception: Spring Famework 4 , Apache tiles 3 and Tomcat 8
Android - Image Buttons cannot be clicked with just a one click
Why Java allows casting obj with Interface [duplicate]
XML not indented on remote server via Java Transformer
How do i take an array list position and turn that into a string?
Proper Use of Keep Alive For Loop
Drools in Android (JavafxPorts)
InflateException: Binary XML file line #52: Error inflating class
Apache Commons Net FTPClient Will Not Execute listFiles()
Encrypting/Decrypting with AES and storing information in text file
how to convert OST file PST file in java?
MapReduce with filename as Key, contents as Values, many small files
Cannot work with AKAZE (OpenCV) on Java

Categories

HOME
java
log4j
winforms
mockito
plot
fft
raspberry-pi
jira
yarn
paw-app
jgroups
survey
gps
ip
ckeditor
ravendb
directx
metatrader4
vault
kentor-authservices
izpack
wheelnav.js
quicklook
timeout
after-effects
visual-composer
jtextfield
nas
swiftlint
autocad-plugin
orleans
facebook-instant-articles
web-sql
blazemeter
brunch
traffic
large-file-upload
media-queries
fog
winrt-xaml-toolkit
code-contracts
textmate
swisscomdev
hockeyapp
sqlite2
tasker
android-tabhost
ibpy
fakeiteasy
netcdf4
angular2-meteor
flickr-api
mplayer
np-complete
media-player
knpmenubundle
topbeat
libpng
log4c
url-masking
nsviewcontroller
essence
ford-fulkerson
reactive-banana
sdhc
t4mvc
retina
sonarqube5.1.2
offloading
typekit
oxwall
xc16
dd
java.util.concurrent
device-manager
php-5.4
fluentautomation
valueconverter
hippomocks
kgdb
rtmfp
resty-gwt
mcts
web2py-modules
plasma
spring-validator
e4x
path-separator
code-cleanup
cufon
netdna-api
boost-filesystem
mod-auth
tomcat-valve
telerik-scheduler
asp.net-profiles
perfect-hash
memory-size
iweb

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App