EclipseLink MOXy: Logical operators in XmlPath annotation - xpath

Do logical operators work in XmlPath annotations of EclipseLink MOXy?
I tried and could not make it work (no Exception is thrown and nothing is bound to "elements").
For example, I would like to have in a bindings file something like this:
<java-type name="Content">
<java-attributes>
<xml-element java-attribute="elements" xml-path="/a/b/ | /c/d"
type="ElementType" container-type="java.util.List" />
</java-attributes>
</java-type>
Is there a way to achieve the same result from a modification of the bindings without using the logical or in the xml-path?
I can only think of a workaround where one would use getters and settings in the domain model, bind both /a/b and /c/d to elements and have the setters append elements to the List rather then replacing the list upon each call to setElements(). I'd rather handle it in the bindings file, though.
Does there exist a place in the documentation that specifies which parts of XPath are supported in MOXy?

Here is an example of how you could support this use case.
Mapping Document (bindings.xml)
You could use the xml-elements mapping for this use case. On each of the nested xml-element mappings you would specify a different xml-path.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum17977009">
<java-types>
<java-type name="Content">
<xml-root-element/>
<java-attributes>
<xml-elements java-attribute="elements">
<xml-element xml-path="a/b"/>
<xml-element xml-path="c/d"/>
</xml-elements>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Java Model (Content)
Below is the Java model we will use for this example.
package forum17977009;
import java.util.List;
public class Content {
private List<ElementType> elements;
public List<ElementType> getElements() {
return elements;
}
public void setElements(List<ElementType> elements) {
this.elements = elements;
}
}
jaxb.properties
To specify MOXy as your JAXB provider you include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Input (input.xml)
Below is a sample input document.
<?xml version="1.0" encoding="UTF-8"?>
<content>
<a>
<b/>
<b/>
</a>
<c>
<d/>
<d/>
</c>
</content>
Demo
Below is some demo code you can run to prove that everything works:
package forum17977009;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum17977009/bindings.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Content.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum17977009/input.xml");
Content content = (Content) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(content, System.out);
}
}
Output
Since all of the items are of the same type, they will output based on the xml-path of the first xml-element in the xml-elements mapping:
<?xml version="1.0" encoding="UTF-8"?>
<content>
<a>
<b/>
<b/>
<b/>
<b/>
</a>
</content>
UPDATE
Does there exist a place in the documentation that specifies which
parts of XPath are supported in MOXy?
Here are some examples that should help:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
We are going to add some validation on the XPath statements that are entered for mappings. You can track our progress on this using the following link:
http://bugs.eclipse.org/397101

Related

About mybatis resultmap incremental mapping behavior change

I am handling mybatis version upgrade. When I upgrade from 3.3.1 to 3.5.1, I found that the automatic mapping behavior of resultMap has changed
here is an example
#Data
public class RequestLog {
private String apiVersion;
private String url;
}
public interface RequestLogMapper {
List<RequestLog> getAll();
}
resultMap
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test.mapper.RequestLogMapper">
<resultMap type="test.entity.RequestLog" id="RequestLogMap">
<result property="apiVersion" column="api_version" jdbcType="VARCHAR"/>
<result property="url" column="url" jdbcType="VARCHAR"/>
</resultMap>
<select id="get" resultMap="RequestLogMap">
select api_version as apiVersion,
url
from request_log
limit 10;
</select>
</mapper>
In this example, an incorrect mapping of apiVersion is defined, but it can be assigned correctly in version 3.3.1, and the result is as follows
RequestLog(apiVersion=V3, url=/buy)
When upgrading to 3.5.1, apiVersion cannot be assigned correctly, and the result is as follows
RequestLog(apiVersion=null, url=/buy)
I read the official documentation and understand that resultMap supports incremental automatic mapping by default, so the wrongly written apiVersion field in version 3.3.1 will be ignore and not affect the automatic mapping rules, but why is the automatic mapping not work in 3.5.1?

How does the # option operator work in AEM HTL templates

I spen a bit of time trying to read the official documentation on the AEM # operator and the official syntax specification, but I do not understand the logic behind.
Let's take this example presented in the documentation:
${myVar # optOne, optTwo=bar}
How will this expression be evaluated? What is the effect of the assignment optTwo=bar?.
Or this example in the syntax specification:
${myVar # optOne, optTwo=myVar, optThree='string', optFour=[myVar, 'string']}
How each assignment in the list (optTwo=myVar, optThree='string', optFour=[myVar, 'string']) will affect the final value to which the expression will be evaluated to?
In my project we are using this # operator to pass values to the Java backend logic. I have created a sample use-case to demonstrate the usage of the # operator.
I have created a simple info component with a textfield, a numberfield and a checkbox. The corresponding cq:dialog's .content.xml is as below -
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Info"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/tabs"
type="nav"/>
<items jcr:primaryType="nt:unstructured">
<tab
jcr:primaryType="nt:unstructured"
jcr:title="Properties"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<columns
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/container">
<items jcr:primaryType="nt:unstructured">
<name
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/textfield"
class="field-whitespace"
fieldDescription="Enter full name of the user"
fieldLabel="Full Name"
name="./fullName"/>
<age
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/numberfield"
class="field-whitespace"
fieldDescription="Enter the age of the user"
fieldLabel="Age"
name="./age"/>
<married
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/form/checkbox"
class="field-whitespace"
fieldDescription="Check if the user is married"
name="./married"
text="Married?"
value="true"/>
</items>
</columns>
</items>
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/foundation/layouts/fixedcolumns"/>
</tab>
</items>
</content>
</jcr:root>
The corresponding HTL file is as below -
<div data-sly-test="${wcmmode.edit || wcmmode.design}">
Info Component
</div>
<sly
data-sly-use.info="${'org.redquark.aem.learning.core.cq.text.InfoComponent' #
fullName=properties.fullName,
age=properties.age,
married=properties.married
}" />
<sly data-sly-test="${info}">
<h1>${info.details}</h1>
</sly>
Here, you can see that in the tag, we are passing values from the JCR in the variables fullName, age and married.
The java code that will read these values is as below -
package org.redquark.aem.learning.core.cq.text;
import com.adobe.cq.sightly.WCMUsePojo;
public class InfoComponent extends WCMUsePojo {
private String details;
#Override
public void activate() throws Exception {
String fullName = get("fullName", String.class);
Integer age = Integer.parseInt(get("age", String.class));
Boolean isMarried = Boolean.parseBoolean(get("married", String.class));
details = fullName + " is " + age + " years old and is " + (isMarried ? "married" : " not married");
}
/**
* #return the details
*/
public String getDetails() {
return details;
}
}
Or if you are using SlingModels instead of Java Use API then you can access those values in a typical Sling Model way.
package org.redquark.aem.learning.core.models.text;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
#Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class InfoModel {
#Inject
#Optional
#Default(values = "Test")
private String fullName;
#Inject
#Optional
#Default(values = "0")
private String age;
#Inject
#Optional
#Named("married")
#Default(values = "false")
private String isMarried;
// Variable that will be read in the HTL file
private String details;
#PostConstruct
protected void init() {
details = fullName + " is " + Integer.parseInt(age) + " years old and is "
+ (Boolean.parseBoolean(isMarried) ? "married" : " not married");
}
/**
* #return the details
*/
public String getDetails() {
return this.details;
}
}
Of course, then you have to call your InfoModel class in the HTL code as
<sly data-sly-use.info="${'org.redquark.aem.learning.core.models.text.InfoModel' #
fullName=properties.fullName,
age=properties.age,
married=properties.married
}" />
You see, here we are reading the same values which were passed in the HTL code. We can then perform any business logic on them.
I hope this helps. Cheers!

Intergrating AEM/CQ5 and Spring Framework?

I have been trying to integrate Spring framework within AEM6/CQ5.
I am following this tutorial. LINK
As per the tutorial I have installed the NEBA package.
All NEBA bundles are active in OSGi console.
Then I created my own Maven CQ5 project, I added the dependencies of Neba annotations and Spring. My project was also successfully deployed in CQ5(bundle is active).
I tried to use a ResourceModel annotation of NEBA. But this model does not appear in the model registry of NEBA.
I mapped the ResourceModel to a content component that i created "linkComponent".
When the user drags and drops this on any parsys the resource node has the properties linkName and linkURL.
I tried accessing these values in JSP but I failed.
Please See code below :
package com.zensar.neba;
import org.apache.sling.api.resource.Resource;
import io.neba.api.annotations.Path;
import io.neba.api.annotations.ResourceModel;
#ResourceModel(types = "zensar-neba/components/content/linkComponent")
public class LinkComponent {
private String linkName;
private String linkURL;
public String getLinkName() {
return linkName;
}
public void setLinkName(String linkName) {
this.linkName = linkName;
}
public String getLinkURL() {
return linkURL;
}
public void setLinkURL(String linkURL) {
this.linkURL = linkURL;
}
}
Please See JSP Code of linkComponent below:
<%#include file="/libs/foundation/global.jsp"%>
<%#taglib prefix="neba" uri="http://neba.io/1.0"%>
<neba:defineObjects />
Link Component
Click Here ${m.linkName}
Then I tried creating an Controller using Spring annotation but I got "Path not found" what am I missing.
Please see code below:
package com.zensar.neba;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class DemoController {
#RequestMapping("/echo/{param}")
#ResponseBody
public String echo(#PathVariable("param") String paramToEcho) {
return "Hello "+ paramToEcho;
}
}
I called the controller link this : http://localhost:4502/bin/mvc.do/echo/Oliver
IMPORTANT NOTE:
All my bundles are active
If all bundles are up and running and you are seeing the model registry, it means everything is running smoothly. But: your model doesn't show up, this means that the application context of your bundle isn't running. NEBA uses gemini-blueprint, the reference implementation of the OSGi blueprint specification.
Do you have an xml file, e.g. blueprint.xml, in the OSGI-INF/blueprint folder of your bundle? It should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.zensar.neba" />
</beans>
If you do, what does your error.log say when your bundle is starting?
For reference, here is a sample webapp using NEBA: https://github.com/unic/publication-neba-adaptto-2015
One more thing: NEBA uses private field injection, so you don't need to have any setters on your bean.
I'm glad to have helped! Just to answer your last question: In a maven project, the right location for the blueprint XML file would be in the src/main/resources/OSGI-INF/blueprint folder of the maven module containing your models / controllers.

Spring Framework auditng fields (CreatedAt, UpdatedAt)

I'm working on a Spring Framework project. For fast development process, I'm using Spring Roo (1.3.2). For several entities, I have requirement to store the creation time and last time it was updated. I've made couple of experiments on Spring Roo tutorial project and this is one of the entities and the way I'm trying to do it.
package com.springsource.roo.pizzashop.domain;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class Topping {
/**
*/
#NotNull
#Size(min = 2)
private String name;
/**
*/
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(style = "M-")
private Date createdAt;
/**
*/
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(style = "M-")
private Date updatedAt;
#PrePersist
protected void onCreate() {
createdAt= new Date();
}
#PreUpdate
protected void onUpdate() {
updatedAt = new Date();
}
}
When I create an object (Topping) it's getting the right value for createdAt and leaving "NULL" for updatedAt. Perfect! That's the way it has to be!
But when I update the object (Topping) it's getting the right value for updatedAt and losing the value of createdAt (NULL).
The problem is that when I update the object I am losing the value of createdAt.
Could you tell me why do I get this behavior? Could you help me with a possible solution for it?
However, createdAt and updatedAt fields don't need to appear in the "view" (create.jspx, update.jspx), so I've set its render attributes to false.
These are the forms for creating and updating.
create.jspx
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<jsp:output omit-xml-declaration="yes"/>
<form:create id="fc_com_springsource_roo_pizzashop_domain_Topping" modelAttribute="topping" path="/toppings" render="${empty dependencies}" z="w4+E4tQPCNRPSYVWPNOBUuf9zNE=">
<field:input field="name" id="c_com_springsource_roo_pizzashop_domain_Topping_name" min="2" required="true" z="GRdEGRLiZ0QLjBH0pTEOZ252BD8="/>
<field:datetime dateTimePattern="${topping_ts_date_format}" field="ts" id="c_com_springsource_roo_pizzashop_domain_Topping_ts" render="false" z="user-managed"/>
<field:datetime dateTimePattern="${topping_updated_date_format}" field="updated" id="c_com_springsource_roo_pizzashop_domain_Topping_updated" render="false" z="user-managed"/>
</form:create>
<form:dependency dependencies="${dependencies}" id="d_com_springsource_roo_pizzashop_domain_Topping" render="${not empty dependencies}" z="bkqRYdlfs3kDAjK51P0O+7NiahE="/>
</div>
update.jspx
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<jsp:output omit-xml-declaration="yes"/>
<form:update id="fu_com_springsource_roo_pizzashop_domain_Topping" modelAttribute="topping" path="/toppings" versionField="Version" z="YGl9ujJNQw182uzoCDgi1FdiafQ=">
<field:input field="name" id="c_com_springsource_roo_pizzashop_domain_Topping_name" min="2" required="true" z="GRdEGRLiZ0QLjBH0pTEOZ252BD8="/>
<field:datetime dateTimePattern="${topping_ts_date_format}" field="ts" id="c_com_springsource_roo_pizzashop_domain_Topping_ts" render="false" z="user-managed"/>
<field:datetime dateTimePattern="${topping_updated_date_format}" field="updated" id="c_com_springsource_roo_pizzashop_domain_Topping_updated" render="false" z="user-managed"/>
</form:update>
</div>
The render="false" on fields tags makes that this fields will not be included on page. So, on POST request, this value is missing and Spring Binding doesn't fill it (take a count that Binding process create new instance of entity, doesn't get it form DB). This makes merge operation to set missing values to null.
For more info about this you can read:
Spring MVC 3.0: How do I bind to a persistent object
Is it possible to update only a subset of attributes on an entity using Spring MVC with JPA?
The easiest workaround is include this value in a hidden input of edit form.
On the other hand, take a look to auditing feature of gvNIX. This feature includes auditing (stores creation/update time stamp and user who done it) and and revision log (using Hibernate Envers).
Good luck!

applying display tag to my project but failed in struts config file

I am applying display tag to my jsp in struts but not able to do it please check out
1.strutsconfig
<form-beans><form-bean name="DailysheetForm" type="com.myapp.struts.DailysheetForm"/>
</formbean>
<action input="/" path="/DailysheetList" name="DailysheetForm" scope="request" type="com.myapp.struts.DialysheetListAction">
<forward name="success" path="/DailysheetList.jsp"/>
</action>
2.Form
public class DailysheetForm extends ActionForm
{
// some getter and setter methods i used like receiptno
protected ArrayList arraylist;
public ArrayList getArraylist()
{
return arraylist;
}
public void setArraylist(ArrayList arraylist) {
this.arraylist = arraylist;
}
3.Action Class
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ArrayList dailysheetdata;
DailysheetForm dailyform = (DailysheetForm) form;
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection("jdbc:mysql://localhost/Stonecrusher?"
+ "user=Stonecrusher&password=xxxxxx");
System.out.println("Connection"+connect);
dailysheetdata = StoneCrusherData.getDailysheetData(connect);
dailyform.setArraylist(dailysheetdata) ;
return mapping.findForward(SUCCESS);
}
JSP
<display:table id="data" name="requestScope.DailysheetForm.arraylist"requestURI="/DailysheetList" pagesize="10" >
<display:column property="receiptno" title="RECEIPTNO" sortable="true"/>
<display:column property="cutomername" title="CUSTOMER NAME" sortable="true"/>
</display:table>
<display:table id="data" name="requestScope.DailysheetForm.arraylist" requestURI="/DailysheetList" pagesize="10" >
<display:column property="receiptno" title="RECEIPTNO" sortable="true"/>
<display:column property="cutomername" title="CUSTOMER NAME" sortable="true"/>
</display:table>
It is not working and basically I am getting data to dailysheetdate which is arraylist in my Action Class and I want to display it in jsp with pagination. I know I was wrong please help me how to do it.
Check your jar files whether you placed all required jars in to lib or not..
still have a problem paste your Error here..
See the Tutorial for Display Tag
then you need not Specify input and name attributes in <action> in strutsconfig.xml
i.e your code should like ethis
<action path="/DailysheetList" scope="request" type="com.myapp.struts.DialysheetListAction">
<forward name="success" path="/DailysheetList.jsp"/>
</action>
then definitely Action Class will execute..
And one more thing by seeing your action class code i does't know whether StoneCrusherData object is created or not.. check below line also
dailysheetdata = StoneCrusherData.getDailysheetData(connect);

Resources