I'm developing a system for dynamically mapping received structured messages to Java objects. Currently I'm doing this via an XML schema, which has the following typical format:
<mapping>
<domainObject>company.app.MyObject</domainObject>
<attribute>
<domainAttribute>myAttr</domainAttribute>
<messageAttribute>root/config/component/param1</messageAttribute>
</attribute>
</mapping>
So the received message has a hierarchical structure, which maps on to specific domain object attributes. So for the above, I'm mapping message element root/config/component/param1 on to domain attribute MyObject.myAttr
I've already developed code to do this, but after reading about Struts2 and its use of OGNL, it seems like it's doing the same thing. My question is, can OGNL dynamically construct the necessary objects, followed by populating all necessary attributes? If so, how is that done? From reading the API docs, it seems that you must construct the objects yourself. For example if I used an OGNL expression like this
rootObj.childObj.param1
Ideally I'd want the OGNL service to construct object rootObj, followed by childObj, then set attribute param1. This is exactly what Struts does to transfer Http request parameters on to domain objects, so dynamic object creation must be happening somewhere. However after doing some experimenting with OGNL expressions, there's no object creation happening, and I get null object exceptions.
OGNL will not construct your objects. It's used primarily and eventually to evaluate expressions. Creating objects is the responsibility by you or framework that used ObjectFactory to create objects.
Related
I am getting started with MapStruct. I am unable to understand when do we use "expression" tag in MapStruct? Why do we have certain mappings where we use "target" tag and "expression" tag? Does it mean that expressions are used when you want to map two or more fields within a bean to a single property/field in the target as mentioned in the documentation "http://mapstruct.org/documentation/stable/reference/html/#expressions"
Expressions are used when you can't map a source - to a target property or when a constant does not apply. MapStruct envisioned that several language could be used to address expressions. However, only plain java is implemented (hence "java(... )" ). EL was envisioned but not yet realised.
A typical use case that I use is generating a UUID. But even there you could try the new #Context to achieve that goal.
Remember, the stuff within the brackets is put directly in the generated code. The IDE can't check its correctness, and you will only spot problems during compilation.
Expressions are IMHO a fallback means / gap filler for stuff that is not yet implemented in MapStruct.
Note: Mapping target-to-source by means of a custom method as suggested in the other answers can be done automatically. MapStruct will recognised the signature (return type, source type) and call your custom method. You can do this in the same interface (default method) or in a used mapper.
In general, MapStruct expressions are used when you simple cannot write a MapStruct mapper. They should be used as a fallback approach when the library doesn't apply to your use-case.
For example, -- as the documentation says -- when a mapping requires more than one source variable, an expression can be used to "inject" them to a mapper method.
Another use case is when the source variable you need to use -- say bar -- is not a part of the source class but a member of one of its variables (here, classVar). You would map it to the target field foo using a custom myCustomMethod method with #Mapping(target="foo", expression="java(myCustomMethod(source.classVar.bar)))".
Whenever I'm using thymeleaf with spring, I find that I can retrieve a property on a map using "." (such as myMap.field). I want to know why it works. Because thymeleaf using spring expression language, and I should use "[]"(such as myMap['field']) on a map.
Thanks for your answer.
When you can access it using dot operator like myMap.field, It is basically the implementation of Map for use when building model data for use with UI tools. Supports chained calls and generation of model attribute names.
This class serves as generic model holder for Servlet MVC but is not tied to it.
So ModelMap: implements Map interface. It also contains Map method.
When the variable is on the left side of the dot, it’s either a Map (something with keys) or a bean (something with properties).
This is true regardless of whether the variable is an implicit object or an attribute.
The thing at the right, the field name is basically the map property or key.
for more details
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/ui/ModelMap.html
https://www.oreilly.com/library/view/head-first-servlets/9780596516680/ch08s23.html
https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dynamic-fields
the answer is like this question!.
add a MapAccessor to evaluation context to use "." on map
The scenario is simple:
UI call RESTful API to get an object tree, then UI change some data and call RESTful API to update it.
But for security or performance reason..., my RESTful API can NOT bring the whole object tree to the UI.
We have two choose for this purpose: creating an individual Java Bean for RESTful API or extend existing business Java Bean plus #JsonIgnore.
The second looks smarter because we re-use business class.
But Now we have a trouble: I need to merge the object from UI with the object from DB, otherwise I will lose some data.
But how do I know which piece of data will come from UI?
I know I can hard code to copy fields one by one.
But this way is dangerous.
I am asking for generic way to avoid hard code to copy fields.
I tried org.apache.commons.beanutils.BeanUtils, but it can't meet the requirement because it always overwrite target fields.
So I am thinking this way:
If the field in UI bean is not Null, then overwrite the value of the same name field in destination bean. but how do I handle if the field is some kind of primitive type like int which have default value 0?
I don't know if the field really carry an UI value 0 or just not comes back from UI.
I tried to convert primitive type to object type, but it still have troubles on boolean type, many java tools don’t support “ Boolean isValid(){…}” like BeanUtils. And this kind converting is dangerous on existing code.
I tried those code:
JacksonAnnotationIntrospector ai = new JacksonAnnotationIntrospector();
AnnotatedClass ac = AnnotatedClass.construct(MyClassDTO.class, ai, null);
String[] ignoredList = ai.findPropertiesToIgnore(ac);
for(String one: ignoredList){
System.out.println(one);
}
but ignoredList is always null. I am using Jackson 1.9.2
You could consider using JsonPatch. We use it and it works quite well. Of course it means you apply patches at the JSON level and not in the bean directly so if you need to support more than just JSON, it might be a problem.
Here's an implementation: https://github.com/fge/json-patch
I found the solution on Jackson:
MyBean defaults = objectMapper.readValue(defaultJson, MyBean.class);
ObjectReader updater = objectMapper.readerForUpdating(defaults);
MyBean merged = updater.readValue(overridesJson);
it comes from :
readerForUpdating
merging on Jackson
I'm getting "JSONRpcClientException: ... circular reference." when serializing my domain objects with JSON. (using jsonrpc1.0).
I'd like to maintain the domain as it is, but need to get JSON-RPC working so I wonder if there is any solution to avoid or skip some fields of a Java class (those circulars) of being serialized to JSON as it is described here for .NET.
Is it posible to use something like ScriptIgnore tags in Java to reach this?
I have a basic JavaBean in my service layer and originally it was not designed for marshalling. This object is used by both JAX-WS, JAX-RS, and Servlets in other layers of my application. I want to take advantage of a drill down type effect in my REST services so my question is: How do I make one of the fields/properties of the javabean appear in the xml as an HTML Link? Obviously I need to use CData. I cannot modify the original javabean by adding fields, etc. Is there an annotation I can use?
If I have in my class:
...
String data;
...
how do I make that(in xml):
<data><![CDATA[ValueOfData]]></data>
is this possible with JAXB and Annotations? Maybe xlink?
I suggest using a type adapter. These are normally used to adapt XML string values into more strongly-typed values like timestamps, but you can also use them to adapt strings to strings.
First, create a subclass of javax.xml.bind.annotation.adapters.XmlAdapter. This class will have to implement marshal and unmarshal, converting to and from the value of your field, and the HTML fragment in the XML.
Once you have that, you can annotate your field with
#XmlJavaTypeAdapter(MyAdapter.class)
And that should be it.