I have my class annotated to accept extra elements in JSON, like this:
#JsonIgnore
private final Map<String, Object> map;
#JsonAnyGetter
public Map<String, Object> map() {
return map;
}
#JsonAnySetter
public Object put(String key, Object value) {
return map.put(key, value);
}
When I deserialize a JSON object like this:
{
"foo" : "bar",
"baz" : "qux"
}
I creates a map with key, value pairs foo, bar and baz, qux.
I would like this class to work for JAXB as well, so that I can serialize/deserialize to JSON and to XML. So this xml should be deserialized to the same map:
<foo>bar</foo>
<baz>qux</baz>
I started off with Jackson for a pure JSON mapping, which is working with the annotations as shown. How can I archieve the same result for XML?
Related
Suppose I have the following Java-class from 3rd party library:
public class Itm {
public final Map<String, String> properties = ['foo': 'bar']
}
With the following code println new Itm().properties I expect to get a Map: [[foo:bar]]
But the result is:
[class:class Itm]
I realized that if I create the same class in Groovy, but declare properties field without public modifier, I get an expected result. But the class I work with has public access modifier. So in this case how can I access public field called properties, not default Groovy's getProperties(Object self)?
You can use Groovy's direct field access operator obj.#field. This operator omits using the getter method and accesses the object field directly. Let's say we have the following Java class:
Itm.java
import java.util.HashMap;
import java.util.Map;
public class Itm {
public final Map<String, String> properties = new HashMap<String,String>() {{
put("foo", "bar");
}};
}
And the following Groovy script that uses it:
println new Itm().#properties
The output is:
[foo:bar]
Is there a way to convert from plain DTO like:
class DTO {
private Set<String> prop;
}
to entity like:
class Entity {
private Nested nested;
}
class Nested {
private Set<String> prop;
}
When I try default configuration nested field remains empty.
What should be configured?
You can use the functionality of the deep mapping
ModelMapper mapper = new ModelMapper();
mapper.createTypeMap(DTO.class, Entity.class)
.addMappings(mapping -> mapping.<Set<String>>map(DTO::getProp, (dest, v) -> dest.getNested().setProp(v)));
mapper.createTypeMap(Entity.class, DTO.class)
.addMappings(mapping -> mapping.map(src -> src.getNested().getProp(), DTO::setProp));
I have the below JSON code that needs to be parsed. I'm using the corresponding JAX-RS models. The problem is that the paymillClient object is null. If I add currency as a string inside the PaymillSubscription object, it returns EUR value, not null. So there appears to be a problem with the PaymillClient object, not plain strings. Could there be a limit to the number of nested objects for parsing ? Ex, max 2 nested objects. So because there are 3 in my case, it doesn't work.
Unfortunately, I cannot change the JSON code that needs to be parsed at all. I just need to make it work with the JAX-RS implementation.
{
"event":{
"event_type":"subscription.succeeded",
"event_resource":{
"subscription":{
"id":"sub_29f144a3bc32c71f96e2",
"offer":{ },
"livemode":false,
"amount":200,
"temp_amount":null,
"currency":"EUR",
"name":"Monthly subscription",
"interval":"1 MONTH",
"trial_start":null,
"trial_end":null,
"period_of_validity":null,
"end_of_period":null,
"next_capture_at":1428939744,
"created_at":1426264944,
"updated_at":1426264944,
"canceled_at":null,
"payment":{ },
"app_id":null,
"is_canceled":false,
"is_deleted":false,
"status":"active",
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
},
"transaction":{ }
},
"created_at":1426264944,
"app_id":null
}
}
PaymillEventContainer:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventContainer
{
private PaymillEvent event;
}
PaymillEvent:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEvent
{
#XmlElement(name = "event_type") #DocumentationExample(value = "subscription.succeeded") private String eventType;
#XmlElement(name = "event_resource") private PaymillEventResource eventResource;
}
PaymillEventResource:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventResource
{
private PaymillClient client;
private PaymillOffer offer;
private PaymillSubscription subscription;
}
PaymillSubscription:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillSubscription
{
private PaymillClient client;
private PaymillOffer offer;
}
PaymillClient:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillClient
{
#DocumentationExample(value = "client_c0c24aa7f97e1b8ed15d") private String id;
}
API endpoint code:
public Response postSubscriptionSucceeded(PaymillEventContainer paymillEventContainer)
{
PaymillEvent paymillEvent = paymillEventContainer.getPaymillEvent();
PaymillEventResource paymillEventResource = paymillEvent.getEventResource();
PaymillSubscription paymillSubscription = paymillEventResource.getSubscription();
PaymillClient paymillClient = paymillSubscription.getPaymillClient();
PaymillOffer paymillOffer = paymillSubscription.getPaymillOffer();
String clientId = paymillClient.getId(); // NullPointerException
}
Ok. I tried to run your code on your machine and also received null (note, that I'm using MOXy to unmarshall JSON). Then, I tried to experiment with it a little and found really funny things:
1. If you will remove all null-valued fields from your JSON, all works just perfect.
2. If you will add another field to PaymillSubscription. I added private Test test, where Test is:
#XmlAccessorType(XmlAccessType.FIELD)
public class Test {
private String id;
}
And will send this "test" object between last null-valued field in subscription object and "client" field:
"test":{"id":"sadas"},
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
Then "test" would be null, but "client" will be parsed as expected.
3. If you will add all null-valued objects into model (I mean, create respective fields in PaymillSubscription class) all works just perfect.
It seems, that by default JAXB specification doesn't allow JSON with unrecognized fields, but MOXy still tries to parse it (and sometimes produces errors).
I have something like the following groovy class :
class Foo {
private Map<String,String> bar = [:]
Map<String, String> getBar() {
return bar.asImmutable()
}
def doSomething(List<String> argValues){
argValues.each {
bar[it] = it
}
}
}
The doSomething method will fail, it seem, in the each closure, the bar property is use trough accessor, not the field. So it's immutable.
The question is "how can i use the field (not the accessor) within the closure ?
Thanks.
You can use the property accessor operator # like so:
this.#bar[ it ] = it
we read in msdn we "Adding new dynamic properties" by using DynamicObject Class
i write a following program
public class DemoDynamicObject : DynamicObject
{
}
class Program
{
public static void Main()
{
dynamic dd = new DemoDynamicObject();
dd.FirstName = "abc";
}
}
But when i run this program it gives runtime error :'DemoDynamicObject' does not contain a definition for 'FirstName'
if we adding dynamic property by using DynamicObject Class then why it can give this error
can anyone tell me reason and solution?
When using DynamicObject as your base class, you should provide specific overrides to TryGetMember and TrySetMember to keep track of the dynamic properties you are creating (based on the DynamicObject MSDN documentation):
class DemoDynamicObject: DynamicObject
{
Dictionary<string, object> dictionary
= new Dictionary<string, object>();
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
string name = binder.Name;
return dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
If you just want to have a dynamic object that you can add properties to, you can simply use an ExpandoObject instance, and skip the custom class inheriting from DynamicObject.