I want to exclude some fields during mapping from a bean to HashMap.
Orika definition:
static {
final MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(MyReq.class, Map.class)
.exclude("myproperty")
.byDefault()
.register();
MAPPER = mapperFactory.getMapperFacade();
}
Bean definitions:
public class MyReq {
private String myproperty;
}
Usage:
MyReq req = new MyReq;
Map map = MAPPER.map(req, Map.class);
Result: the Map contains the excluded myproperty field! Why?
I also faced this problem, but only with Map instances (it works OK when class that you defined is destination object). However, there is a workaround, since Orika has multiple ways to define mapping rules, something like this:
mapperFactory.classMap(MyReq.class, Map.class)
.fieldMap("myproperty").exclude().add()
.byDefault()
.register();
Related
These two are Service classes, which makes http calls to other services to retreive the json response. Just wanted to know if this is a proper way to use ResourceConverter which helps to convert json response string to POJO.
bIf you notice, these two seperate classes contains its own ResourceConverter Bean method. I cant create a single method which can be shared by all classes, because we need DummyResponse.class and TestResponse.class as the parameter. So, Is this way acceptable? Is it good practise to have multiple bean methods which return the same type, but in different classes?
#Service
public class TestClient(){
#Bean
private ResourceConverter getTestResponseConverter(){
ObjectMapper mapper = new ObjectMapper();
mapper.setDeserialization(DeserializationFeature.ALLOW_UNKNOWN_PROPERTIES);
ResourceConverter converter = new ResourceConverter(mapper,TestResponse.class);
return converter;
}
private TestResponse getTestResponse(){
//okhttp call to get the json, this is not actual syntax for call, not relevant in this context
String responseBodyString = okhttp.call(request);
JSONAPIDocument<TestResponse> testDocument = getTestResponseConverter().readDocument(responseBodyString, TestResponse.class);
return testDocument.get();
}
}
#Service
public class DummyClient(){
#Bean
private ResourceConverter getDummyResponseConverter(){
ObjectMapper mapper = new ObjectMapper();
mapper.setDeserialization(DeserializationFeature.ALLOW_UNKNOWN_PROPERTIES);
ResourceConverter converter = new ResourceConverter(mapper,DummyResponse.class);
return converter;
}
private Dummy getDummyResponse(){
//okhttp call to get the json, this is not actual syntax for call, not relevant in this context
String responseBodyString = okhttp.call(request);
JSONAPIDocument<DummyResponse> dummyDocument = getDummyResponseConverter().readDocument(responseBodyString, DummyResponse.class);
return testDocument.get();
}
}
You should/can use #Primary to annotate the one that will take precedence if there is an #Autowired ResourceConverter... and Spring can't tell the difference.
You can use #Qualifier to "name" each one and then the same annotation on the #Autowired bean to get the one you want.
So:
#Bean
private ResourceConverter testResponseConverter(){
...
}
and
#Bean
#Primary
private ResourceConverter dummyResponseConverter(){
...
}
You can do:
#Autowired ResourceConverter rc; // Gets the #Primary dummy one
#Autowired #Qualifier("testResponseConverter") ResourceConverter rc2; // Gets the corresponding testResponseConverter
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html
I've got problem similar to this:
Kafka Deserialize Nested Generic Types
In my kafka producer I am sending object that looks like this:
public class ExternalTO implements Serializable
{
private static final long serialVersionUID = 7949808917892350503L;
private List<IExternalData> externalDatas;
public ExternalTO()
{}
}
The cornerstone is this: List<IExternalData> externalDatas.
This interface looks like:
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public interface IExternalData
{
String getOne();
}
In my application there can by generated multiple types of IExternalBetData interface implementations (about 10 different). In this case, for instance, my producer generated ExternalTO with inner list of ConcreteExternalData objects. Sent JSON looks like:
{
"externalDatas":
[{"#class":"com.api.external.to.ConcreteExternalData",
"one":false,
"two":false}]
}
Field #class was added because of #JsonTypeInfo annotation, and I thought that this is enough for deserializer to "understend" what type of IExternalData to use in deserialization.
Unfortunately, on the side of kafka listener I am getting the exception:
Cannot construct instance of com.api.external.to.IExternalData (no
Creators, like default construct, exist): abstract types either need
to be mapped to concrete types, have custom deserializer, or contain
additional type information
Consumer looks similar to:
#Service
public class Consumer
{
private final ObjectMapper objectMapper;
public Consumer(ObjectMapper objectMapper)
{
this.objectMapper = objectMapper;
}
#KafkaListener(topics = {"${kafka.topic}"})
public void listen(ConsumerRecord<String, String> record)
{
objectMapper.readValue(record.value(), ExternalTO.class)
}
Please, help to solve this issue with deseriatization.
The deserializer doesn't know, out of all the implementations of IExternalData, to which it should deserialize the consumer record data to. We must resolve that ambiguity.
I was able to resolve this using #JsonDeserialize annotation.
#JsonDeserialize(as = <Implementation>.class
above the declaration of the List
The solution for me was to set property to objectMapper.
ObjectMapper mapper = new ObjectMapper();
// deserializes IExternalData into certain implementation.
mapper.enableDefaultTyping();
There are several previous questions around using JaxB to marshall/unmarshall a java.util.Map, many of which get pointed back to this example, which works great:
http://blog.bdoughan.com/2013/03/jaxb-and-javautilmap.html
However, I can't get JaxB to be able to marshall/unmarshall instances of Map if the map is not a member of the #XmlRootElement. For example, here's a root element class,
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class Customer {
private MyField myField
MyField getMyField() {
return myField
}
void setMyField(MyField myField) {
this.myField = myField
}
}
The definition of it's field class:
#XmlAccessorType(XmlAccessType.FIELD)
public static class MyField{
Map<String, String> getSomeMap() {
return someMap
}
void setSomeMap(Map<String, String> someMap) {
this.someMap = someMap
}
#XmlElement
private Map<String, String> someMap = new HashMap<String, String>()
}
And some code to drive the marshalling:
JAXBContext jc = JAXBContext.newInstance(Customer.class)
Customer customer = new Customer()
MyField myField1 = new MyField()
myField1.someMap.put("foo", "bar")
myField1.someMap.put("baz", "qux")
customer.myField = myField1
Marshaller marshaller = jc.createMarshaller()
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true)
marshaller.marshal(customer, System.out)
This example results in:
java.util.Map is an interface, and JAXB can't handle interfaces.
java.util.Map does not have a no-arg default constructor.
I am writing my code in Groovy rather than Java, but I don't think it should make much of a difference.
I was able to encounter the same behavior using JAXB by creating a TestController of type #RestController, using Spring Boot.
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
#RestController
#RequestMapping(value = "test")
class TestController {
#RequestMapping(value = "findList")
List findList() {
["Test1", "Test2", "Test3"] as ArrayList<String>
}
#RequestMapping(value = "findMap")
Map findMap() {
["T1":"Test1", "T2":"Test2", "T3":"Test3"] as HashMap<String,String>
}
#RequestMapping(value = "")
String find(){
"Test Something"
}
}
With JAXB as the default implementation in SpringBoot, I could reproduce the issue that the /test/findList would correctly render XML, but /test/findMap would generate an error as described in the initial posting.
For me, the solution to the problem is to switch the XML rendering library to Jackson (there are others like XStream as well).
Using Gradle for the build file (build.gradle), I simply add the Jackson dependencies, very similar to how you would if using Maven:
'com.fasterxml.jackson.core:jackson-core:2.7.1',
'com.fasterxml.jackson.core:jackson-annotations:2.7.1',
'com.fasterxml.jackson.core:jackson-databind:2.7.1-1',
'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.7.1',
'org.codehaus.woodstox:woodstox-core-asl:4.4.1',
I have experienced this before myself. Bottom line is that the warning is telling you exactly the problem. You have defined your field as type java.util.Map. JAXB does not support interfaces. To correct your problem, you need to change the declaration of your field to a concrete Map type like:
private HashMap<String, String> someMap = new HashMap<String, String>()
Your other option is described in the link you referenced. You need to have a
MapAdapter class as referenced in the link you provided and then include that in the annotation, hinting to JAXB how it should marshal/unmarshal the Map type.
I think this link gives a clearer example of how to create and implement the MapAdapter:
JAXB: how to marshall map into <key>value</key>
The answer to the specific issue I was having ended up being removing the #XmlElement annotation from the Map field like so:
#XmlAccessorType(XmlAccessType.FIELD)
public static class MyField{
Map<String, String> getSomeMap() {
return someMap
}
void setSomeMap(Map<String, String> someMap) {
this.someMap = someMap
}
//#XmlElement Remove this annotation
private Map<String, String> someMap = new HashMap<String, String>()
}
Without that annotation, the marshalling/unmarshalling works fine, and still interprets the Map as an XmlElement - there seems to be a bug with that annotation specifically. However, as #dlcole points out, an alternative (that would allow you to have more control over the format of your serialized representation) is to use Jackson rather than JAXB.
I'm trying to override property name specified in #JsonProperty during serialization, but get both old and new named properties in the resulting json.
Entity:
class Bean {
#JsonProperty("p")
String prop;
#JsonCreator
Bean(#JsonProperty("p") String prop) {
this.prop = prop;
}
}
Serializing code:
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return "prop";
}
});
System.out.println(mapper.writeValueAsString(new Bean("test")));
Results in:
{"p":"test","prop":"test"}
Accrding to Jackson's code, this happens because constructor parameters are also annotated with #JsonProperty. I'm using Jackson 1.9.5.
Is there a way to disable constructor parameters and get {"prop":"test"} ?
Thanks for help in advance!
There is no way to directly disable annotations, but if you want to block their effects, you can sub-class JacksonAnnotationIntrospector, and override logic used for finding #JsonProperty annotation (or #JsonCreator).
I have annotated an endpoint with swagger annotations. In the #ResponseHeader I set the returning class as response. This class contains a property which is annotated with #XmlJavaTypeAdapter. The adapter is changing the data type of the property. Unfortunately Swagger shows the type of the property, not the return type of the Adapter. Is it possible to do this?
What I already tried is to annotate the property with #ApiModelProperty(). But it was not possible for me to set the dataType to List (Primitive data types or just a list was working).
Thanks :)
The following was not working:
#ApiModelProperty(dataType = "List<Map<String, String>>")
public Map<String, String> someMap = new HashMap<>();
I had to create an Interface
public interface ListOfMap extends List<Map<String, String>> {}
And then I used this interface in the ApiModelProperty:
#ApiModelProperty(dataType = "ListOfMap")
public Map<String, String> someMap = new HashMap<>();
With this, everything worked :)