Another Jaxb binding question - binding

I think I have finally narrowed down one of my problems. I am using Jaxb w/Moxy implementation. I am using Xpath notation in my binding file. I am not getting the desired results.
The original jaxb generated class is heavily nested, for the sake of testing, I slimmed down the code to the below Condition.java.
Condition.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "condition", propOrder = {
"diagnosisPriority",
"problemDate",
"problemType",
"problemName",
"problemCode",
"ageAtOnset",
"problemStatus",
"comment"
})
public class Condition {
protected BigInteger diagnosisPriority;
protected IvlTs problemDate;
protected Cd problemType;
#XmlElement(required = true)
protected Object problemName;
protected Cd problemCode;
protected BigInteger ageAtOnset;
protected Ce problemStatus;
protected List<Comment> comment;
//ommitted getters and setters
Class I created: conditionConnect.java
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class conditionConnect {
private Condition connectX;
public Condition getconditionConnect() {
return connectX;
}
public void setconditionConnect(Condition connectX) {
this.connectX = connectX;
}
}
My first test was to create an object model, and marshall it to xml. This was done successfully with the code below:
public static void main(String[] args) {
try {
int AgeInt = 36;
int DiagnoseInt = 5;
Condition InstCon = new Condition();
Cd myProblem = new Cd();
InstCon.setDiagnosisPriority(BigInteger.valueOf(DiagnoseInt));
InstCon.setProblemType(myProblem);
InstCon.setProblemName("I have Asthma");
InstCon.setAgeAtOnset(BigInteger.valueOf(AgeInt));
myProblem.setCode("1223343");
myProblem.setCodeSystem("23433.23232.23232");
myProblem.setDisplayName("Asthma");
myProblem.setCodeSystemName("ICD-9");
JAXBContext jc1 = JAXBContext.newInstance(conditionConnect.class);
Marshaller marshaller1 = jc1.createMarshaller();
marshaller1.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
conditionConnect conVar = new conditionConnect();
conVar.setconditionConnect(InstCon);
marshaller1.marshal(conVar, System.out);
Output is so (success!):
<conditionConnect>
<diagnosisPriority>5</ns0:diagnosisPriority>
<problemType code="1223343" displayName="Asthma" codeSystem="23433.23232.23232" codeSystemName="ICD-9"/>
<problemName>I have Asthma</ns0:problemName>
<ageAtOnset>36</ageAtOnset>
</conditionConnect>
As I will be receiving data via xml string/file, I opted to use a binding file. An excerpt supplied for the Condition class is as follows
problem.xml - data input
<PROBLEM_MODULE>
<ID>91</ID>
<PR_ID>124</PR_ID>
<PROBLEM_TYPE>T</PROBLEM_TYPE>
<PROBLEM_NAME>Asthma</PROBLEM_NAME>
<PROBLEM_CODE>244.9</PROBLEM_CODE>
<PATIENT_AWARENESS>N</PATIENT_AWARENESS>
<TREATING_PROVIDER_ID>23456</TREATING_PROVIDER_ID>
<PROBLEM_CS>ICD9</PCM_PROBLEM_CS>
</PROBLEM_MODULE>
my binding file (conditionsBinding.xml)
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="hl7.astm.greenccd.org"
xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Condition" >
<xml-root-element name="PROBLEM_MODULE" />
<xml-type prop-order="diagnosisPriority problemDate problemType problemName problemCode ageAtOnset problemStatus comment"/>
<java-attributes>
<xml-element java-attribute="diagnosisPriority" xml-path="ID/text()" />
<xml-element java-attribute="problemDate" />
<xml-element java-attribute="problemType" name="PROBLEM_TYPE" type="Cd"/>
<xml-element java-attribute="problemName" />
<xml-element java-attribute="problemCode" />
<xml-element java-attribute="ageAtOnset" xml-path="PCM_TREATING_PROVIDER_ID/text()" />
<xml-element java-attribute="problemStatus" />
<xml-element java-attribute="comment" />
</java-attributes>
</java-type>
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName"/>
<java-attributes>
<xml-attribute java-attribute="code" xml-path="PR_ID/text()"/>
<xml-attribute java-attribute="codeSystem" xml-path="PROBLEM_CODE/text()"/>
<xml-attribute java-attribute="displayName" xml-path="PROBLEM_NAME/text()"/>
<xml-attribute java-attribute="codeSystemName" xml-path="PCM_PROBLEM_CS/text()"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
The Main Code w/ binding and xml input:
public static void main(String[] args) {
try {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/conditions/exec/conditionsBinding.xml"));
JAXBContext jc = JAXBContext.newInstance(new Class[] {Condition.class, Cd.class}, properties);
Unmarshaller u = jc.createUnmarshaller();
Condition conditionInput = (Condition) u.unmarshal(
new File("src/conditions/exec/problems.xml"));
//Marshall Code
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/conditions/exec/binding.xml"));
JAXBContext resultJC = JAXBContext.newInstance(new Class[] {Condition.class}, properties);
Marshaller resultMarshaller = resultJC.createMarshaller();
resultMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
resultMarshaller.marshal(conditionInput, System.out);
Output from above main code:
<Condition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<diagnosisPriority>91</diagnosisPriority>
<problemType/>
<ageAtOnset>23456</ageAtOnset>
</Condition>
THE PROBLEM:
When doing the binding, the tag
<problemType/>
Comes out empty, I am attempting to link Cd to problemType, so the xml output from problemType should be as so:
<problemType code="1223343" displayName="Asthma" codeSystem="23433.23232.23232" codeSystemName="ICD-9"/>
Please advise what I am missing from the binding file.
EDIT:
binding.xml file. I use this file to marshal the xml element names to the variable names in the java objects:
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="hl7.astm.greenccd.org"
xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Condition" xml-accessor-type="FIELD">
<xml-root-element name="Condition"/>
</java-type>
<java-type name="Cd" xml-accessor-type="FIELD">
<xml-root-element name="problemType"/>
</java-type>
</java-types>
</xml-bindings>
Note: I have tested the code without binding.xml, and it gave me the same results w/ different element names. The Main.java code without the binding.xml is as follows:
public static void main(String[] args) {
try {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/conditions/exec/conditionsBinding.xml"));
JAXBContext jc = JAXBContext.newInstance(new Class[] {Condition.class, Cd.class}, properties);
// create an Unmarshaller
Unmarshaller u = jc.createUnmarshaller();
Condition conditionInput = (Condition) u.unmarshal(
new File("src/conditions/exec/problems.xml"));
Marshaller resultMarshaller = jc.createMarshaller();
resultMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
resultMarshaller.marshal(conditionInput, System.out);
} catch (JAXBException je) {
je.printStackTrace();
}
}
Output without the binding.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<PROBLEM_MODULE>
<ID>91</ID>
<PROBLEM_TYPE/>
<TREATING_PROVIDER_ID>23456</TREATING_PROVIDER_ID>
</PROBLEM_MODULE>
The mapping of the Java Class / Field names to the problems.xml file is as follows:
<PROBLEM_MODULE>
<ID>91</ID> /* maps to class Condition: diagnosisPriority */
<PR_ID>124</PR_ID> /* maps to class Cd: code */
<PROBLEM_TYPE>T</PROBLEM_TYPE> /* class Condition: problemType - problemType is of type Cd.java - Cd.java is a list of attributes only
<PROBLEM_NAME>Asthma</PROBLEM_NAME> /* maps to class Cd: displayName*/
<PROBLEM_CODE>244.9</PROBLEM_CODE>/* maps to class Cd: codeSystem*/
<PATIENT_AWARENESS>N</PATIENT_AWARENESS>
<TREATING_PROVIDER_ID>23456</TREATING_PROVIDER_ID> /* maps to Condition: ageAtOnset */
<PROBLEM_CS>ICD9</PCM_PROBLEM_CS> /* maps to class Cd: codeSystemName*/
</PROBLEM_MODULE>
Further Note in the problems.xml file, for:
<PROBLEM_TYPE>T</PROBLEM_TYPE> /* class Condition: problemType - problemType is of type Cd.java - Cd.java is a list of attributes only
In my conditionsBinding.xml file, I have Problem_Type coded as follows:
<xml-element java-attribute="problemType" name="PROBLEM_TYPE" type="Cd"/>
The reason I did this is that Problem_Type has no root element or name="some_field", I initially tried doing in conditionsBinding.xml:
<xml-element java-attribute="problemType" type="Cd"/>
When I did that, I got no line of code for problemType, so I added a name="some_field" to test perhaps that may be my problem. I am following the examples in the moxy wiki, but there is something obvious that I am missing but I can't pinpoint it.
ADDITIONAL EDIT:
After changing the conditionsBinding.xml via the below supplied answer, I was able to get the same xml output. However, problemType should be a list of attributes, so I changed the code to the following:
conditionsBinding.xml
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="hl7.astm.greenccd.org" xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Condition">
<xml-root-element name="PROBLEM_MODULE" />
<xml-type
prop-order="diagnosisPriority problemDate problemType problemName problemCode ageAtOnset problemStatus comment" />
<java-attributes>
<xml-element java-attribute="diagnosisPriority"
xml-path="ID/text()" />
<xml-element java-attribute="problemDate" />
<xml-element java-attribute="problemType" name="PROBLEM_TYPE"
xml-path="." />
<xml-element java-attribute="problemName" />
<xml-element java-attribute="problemCode" />
<xml-element java-attribute="ageAtOnset" name="PCM_TREATING_PROVIDER_ID" />
<xml-element java-attribute="problemStatus" />
<xml-element java-attribute="comment" />
</java-attributes>
</java-type>
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName" />
<java-attributes>
<xml-attribute java-attribute="code" name="PR_ID" />
<xml-attribute java-attribute="codeSystem" name="PROBLEM_CODE" />
<xml-attribute java-attribute="displayName" name="PROBLEM_NAME" />
<xml-attribute java-attribute="codeSystemName" name="PCM_PROBLEM_CS" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
The output came as follows (empty problemType tag):
<?xml version="1.0" encoding="UTF-8"?>
<Condition>
<diagnosisPriority>91</diagnosisPriority>
<problemType />
<ageAtOnset>23456</ageAtOnset>
</Condition>
Excerpt of Cd.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "cd", propOrder = {
"originalText",
"qualifier"
})
public class Cd {
protected Object originalText;
protected List<Qualifier> qualifier;
#XmlAttribute(name = "code")
#XmlSchemaType(name = "anySimpleType")
protected String code;
#XmlAttribute(name = "displayName")
#XmlSchemaType(name = "anySimpleType")
protected String displayName;
#XmlAttribute(name = "codeSystem")
#XmlSchemaType(name = "anySimpleType")
protected String codeSystem;
#XmlAttribute(name = "codeSystemName")
#XmlSchemaType(name = "anySimpleType")
protected String codeSystemName;
#XmlAttribute(name = "nullFlavor")
protected NullFlavorType nullFlavor;
On another note, I realize is that I will need to later annotate problemCode, which is also a field in Conditions.java AND of type Cd, but will be mapped to different xml element names. Which would require another annotation block of Cd.java in the conditionsBinding.xml file. (Mappings are not real, but it will reflect something like the following:
Pseudo conditionsBinding.xml:
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="hl7.astm.greenccd.org" xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Condition">
<xml-root-element name="PROBLEM_MODULE" />
<xml-type
prop-order="diagnosisPriority problemDate problemType problemName problemCode ageAtOnset problemStatus comment" />
<java-attributes>
<xml-element java-attribute="diagnosisPriority"
xml-path="ID/text()" />
<xml-element java-attribute="problemDate" />
<xml-element java-attribute="problemType" name="PROBLEM_TYPE"
xml-path="." />
<xml-element java-attribute="problemName" />
<xml-element java-attribute="problemCode" name="PROBLEM_CODE_PSEUDO"
xml-path="."/>
<xml-element java-attribute="ageAtOnset" name="PCM_TREATING_PROVIDER_ID" />
<xml-element java-attribute="problemStatus" />
<xml-element java-attribute="comment" />
</java-attributes>
</java-type>
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName" />
<java-attributes>
<xml-element java-attribute="code" name="PR_ID" />
<xml-element java-attribute="codeSystem" name="PROBLEM_CODE" />
<xml-element java-attribute="displayName" name="PROBLEM_NAME" />
<xml-element java-attribute="codeSystemName" name="PCM_PROBLEM_CS" />
</java-attributes>
</java-type>
/* java-type name = Cd will be mapped to different xml elements for problemCode */
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName" />
<java-attributes>
<xml-element java-attribute="code" name="PR_ID_PSEUDO" />
<xml-element java-attribute="codeSystem" name="PROBLEM_CODE_PSEUDO" />
<xml-element java-attribute="displayName" name="PROBLEM_NAME_PSEUDO" />
<xml-element java-attribute="codeSystemName" name="PCM_PROBLEM_CS_PSEUDO" />
</java-attributes>
</java-type>
</java-types>
It is making me think my approach needs to be tweaked (not soley depending on binding). I was reading through the moxy user guide at
http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy . I have studied and considered the following options:
JPA (using SAX/DOM - meet in the middle mapping), xml-join-nodes, and xml-adapter. I am not totally clear which of these options (if any) would help with my issue, your expert advice is highly appreciated.

UPDATE
In your example you are using binding.xml to control the mapping for marshalling. In this binding file you have set xml-mapping-metadata-complete="true". This flags to MOXy that the annotations should be ignored and that the binding file specifies the complete metadata. It this flag is set to false or not specified then the binding file is used to augment the annotations.
binding.xml
Below I have removed xml-mapping-metadata-complete="true":
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="hl7.astm.greenccd.org">
<java-types>
<java-type name="Condition" xml-accessor-type="FIELD">
<xml-root-element name="Condition" />
</java-type>
<java-type name="Cd" xml-accessor-type="FIELD">
<xml-root-element name="problemType" />
</java-type>
</java-types>
</xml-bindings>
Output
Now the problemType data appears as attributes:
<?xml version="1.0" encoding="UTF-8"?>
<Condition>
<diagnosisPriority>91</diagnosisPriority>
<problemType code="124" displayName="Asthma" codeSystem="244.9" codeSystemName="ICD9"/>
</Condition>
The following should help:
conditionsBinding.xml
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="hl7.astm.greenccd.org" xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Condition">
<xml-root-element name="PROBLEM_MODULE" />
<xml-type
prop-order="diagnosisPriority problemDate problemType problemName problemCode ageAtOnset problemStatus comment" />
<java-attributes>
<xml-element java-attribute="diagnosisPriority"
xml-path="ID/text()" />
<xml-element java-attribute="problemDate" />
<xml-element java-attribute="problemType" name="PROBLEM_TYPE"
xml-path="." />
<xml-element java-attribute="problemName" />
<xml-element java-attribute="problemCode" />
<xml-element java-attribute="ageAtOnset" name="PCM_TREATING_PROVIDER_ID" />
<xml-element java-attribute="problemStatus" />
<xml-element java-attribute="comment" />
</java-attributes>
</java-type>
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName" />
<java-attributes>
<xml-element java-attribute="code" name="PR_ID" />
<xml-element java-attribute="codeSystem" name="PROBLEM_CODE" />
<xml-element java-attribute="displayName" name="PROBLEM_NAME" />
<xml-element java-attribute="codeSystemName" name="PCM_PROBLEM_CS" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
When I use it with your code I get:
<?xml version="1.0" encoding="UTF-8"?>
<Condition>
<diagnosisPriority>91</diagnosisPriority>
<problemType>
<code>124</code>
<codeSystem>244.9</codeSystem>
<displayName>Asthma</displayName>
<codeSystemName>ICD9</codeSystemName>
</problemType>
</Condition>

Related

Change casing of JSON properties between api versions using Microsoft's ASP.NET API Versioning for Web API 2 and ODATA?

I am introducing API versioning to an existing API. The existing JSON uses Pascal casing for its property names e.g. "FooBar": "foo". For v2 of the API, I would like to use the common camel casing, "fooBar": "foo". I need to keep v1 Pascal casing so that it does not impact any client that is already pulling that version of the API.
My project is
ASP.NET MVC 5.2.7
ASP.NET WEB API 5.2.7
ASP.NET ODATA 7.4.0
ASP.NET WEB API Versioning 4.0.0
My configuration is as follows
public static class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
configuration.AddApiVersioning(options => options.ReportApiVersions = true);
var modelBuilder = new VersionedODataModelBuilder(configuration);
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => typeof(IModelConfiguration).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.ForEach(t => modelBuilder.ModelConfigurations.Add((IModelConfiguration)Activator.CreateInstance(t)));
var models = modelBuilder.GetEdmModels();
configuration.MapVersionedODataRoutes("odata-bypath", "api/v{apiVersion}", models, builder =>
{
builder.AddService<IODataPathHandler>(Singleton, sp => new DefaultODataPathHandler { UrlKeyDelimiter = Parentheses });
builder.AddService<ODataUriResolver>(Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver { EnableCaseInsensitive = true });
});
configuration.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
configuration.MapHttpAttributeRoutes();
}
}
After reading through the docs and specifically Versioned ODataModelBuilder I have not found a way to change the casing based on which version of the API the model is being built for. I can get it to be all Pascal casing or all camel casing, but not v1 Pascal casing and v2 camel casing.
Adjusting the above configuration
var modelBuilder = new VersionedODataModelBuilder( configuration )
{
ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase()
};
would use camel casing (yes I know the explicit call is unnecessary since it is the default). Then I built my own extension method ODataConventialModelBuilder().EnablePascalCase() that mimicked EnableLowerCamelCase() method to get Pascal casing to work.
var modelBuilder = new VersionedODataModelBuilder( configuration )
{
ModelBuilderFactory = () => new ODataConventionModelBuilder().EnablePascalCase()
};
However, I could never find a way to know which version of the API I was building the model for.
At one point, I thought I had it using OnModelCreating to add
((ODataConventionModelBuilder) builder).OnModelCreating += new PascalCaser().ApplyCase;
to each of the v1 IModelConfiguration classes, but it didn't work once I was building multiple models.
Is there a way to change the JSON property naming based on which API version the model is for?
Using the OData Model Configurations approach described here
first add a class that derives from IModelConfiguration to your project.
Something like this:
public class VersionedModelConfiguration : IModelConfiguration
{
private void ConfigureV1(ODataModelBuilder builder)
{
builder.EntitySet<Product>("Products");
}
private void ConfigureV2(ODataModelBuilder builder)
{
if (builder.GetType().Equals(typeof(ODataConventionModelBuilder)))
{
((ODataConventionModelBuilder)builder).EnableLowerCamelCase();
}
builder.EntitySet<Product>("Products");
}
public void Apply(ODataModelBuilder builder, ApiVersion apiVersion)
{
switch (apiVersion.MajorVersion)
{
case 1:
ConfigureV1(builder);
break;
case 2:
ConfigureV2(builder);
break;
default:
ConfigureV1(builder);
break;
}
}
}
Then in Register method:
// ...
var modelBuilder = new VersionedODataModelBuilder(configuration)
{
ModelBuilderFactory = () => new ODataConventionModelBuilder(),
ModelConfigurations = { new VersionedModelConfiguration() }
};
var models = modelBuilder.GetEdmModels();
// ...
Don't be tempted to leave out the line ModelBuilderFactory = () => new ODataConventionModelBuilder()
/api/v1/$metadata:
<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="NS.Models">
<EntityType Name="Product">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" />
</EntityType>
</Schema>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
<EntityContainer Name="Container">
<EntitySet Name="Products" EntityType="NS.Models.Product" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
/api/v2/$metadata:
<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="NS.Models">
<EntityType Name="Product">
<Key>
<PropertyRef Name="id" />
</Key>
<Property Name="id" Type="Edm.Int32" Nullable="false" />
<Property Name="name" Type="Edm.String" />
</EntityType>
</Schema>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
<EntityContainer Name="Container">
<EntitySet Name="Products" EntityType="NS.Models.Product" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

confirm-ack and confirm-nack channel not getting invoked

I am trying to configure the ack & nack channel and am getting the error like
"Only one confirm call back channel can be configured at a time"
Below are the things which I tried:
1. confirm-correlation-expression="#root" //no result found
2. Changed the amqp template like below
<rabbit:connection-factory id="connectionFactory" host="localhost" publisher-confirms="true" publisher-returns="true" />
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" mandatory="true" /> <!-- for nacks -->
<rabbit:admin connection-factory="connectionFactory" />
/>
The error was not there but the ack channel is not getting invoked.
Can anyone help me on this?
Here the MQ config
<rabbit:template id="nonTransactionalRabbitTemplate"
connection-factory="nonTransactionalConnectionFactory"
mandatory="true"
channel-transacted="false"
confirm-callback="confirmCallback"
return-call`enter code here`back="returnCallback" />
<rabbit:connection-factory id="nonTransactionalConnectionFactory"
connection-factory="rabbitClientConnectionFactory"
publisher-confirms="true"
publisher-returns="true"/>
<rabbit:connection-factory id="nonTransactionalConnectionFactory"
connection-factory="rabbitClientConnectionFactory"
publisher-confirms="true"
publisher-returns="true"/>
<bean id="rabbitClientConnectionFactory" class="com.rabbitmq.client.ConnectionFactory" >
<property name="uri" value="${mq.uri}" />
<property name="requestedHeartbeat" value="30" />
</bean>
Here is my outbound adapter
<int-amqp:outbound-channel-adapter channel="abc"
routing-key="xyz"
amqp-template="amqpTemplate"
confirm-correlation-expression="payload"
confirm-ack-channel="successRespTransformChannel"
confirm-nack-channel="failureRespTransformChannel"
return-channel="failureRespTransformChannel"
mapped-request-headers="*"
Here is my service activator
<chain input-channel="successRespTransformChannel">
<int:header-enricher>
<error-channel ref="failed-publishing" />
</int:header-enricher>
<service-activator id="successResp" expression="#abc.addRequestTracking(payload.id,'success')"/>
</chain>
When using the template in the adapter, you must NOT set your own callbacks
confirm-callback="confirmCallback"
return-callback="returnCallback" />
The adapter sets itself as the callback for both confirms and returns. This fails since you have already set the callbacks.
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" mandatory="true" /> <!-- for nacks -->
mandatory enables returns, not nacks.
EDIT
I have no idea what you are doing wrong. I just wrote a quick test case...
#SpringBootApplication
#ImportResource("context.xml")
public class So36546646Application {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(So36546646Application.class, args);
ctx.getBean("out", MessageChannel.class).send(new GenericMessage<>("foo"));
boolean received = ctx.getBean(MyService.class).latch.await(10, TimeUnit.SECONDS);
if (!received) {
System.err.println("Did not receive ack");
}
ctx.getBean(RabbitAdmin.class).deleteQueue(ctx.getBean(Queue.class).getName());
ctx.close();
}
public static class MyService {
private final CountDownLatch latch = new CountDownLatch(1);
public void handle(Message<?> ack) {
System.out.println("ack:" + ack);
latch.countDown();
}
}
}
and
<?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:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/integration/amqp http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<rabbit:connection-factory id="cf" publisher-confirms="true" publisher-returns="true" host="localhost" />
<rabbit:template id="t" connection-factory="cf" mandatory="true" />
<rabbit:admin connection-factory="cf" />
<rabbit:queue id="anon" />
<int:channel id="out" />
<int-amqp:outbound-channel-adapter
channel="out"
amqp-template="t"
routing-key="#{anon.name}"
confirm-correlation-expression="payload"
confirm-ack-channel="acks"
confirm-nack-channel="acks"
return-channel="returns" />
<int:service-activator input-channel="acks" ref="service" />
<bean id="service" class="com.example.So36546646Application$MyService" />
<int:channel id="returns">
<int:queue />
</int:channel>
</beans>
and it worked fine:
ack:GenericMessage [payload=foo, headers={amqp_publishConfirm=true, id=5eed89bf-11b6-76a5-34ed-0091c6bac2c8, timestamp=1460464254229}]

Target Value on Composite Component Error on Updating entity

I am getting a strange error.
I created a simple JSF composite component, that is:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<cc:interface>
<cc:attribute name="fieldId" required="true" />
<cc:attribute name="targetValue" type="java.sql.Date" required="true" />
<cc:attribute name="required" default="false" />
<cc:attribute name="disabled" default="false" />
<cc:attribute name="styleClass" />
</cc:interface>
<cc:implementation>
<p:calendar id="#{cc.attrs.fieldId}" disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}" locale="pt" navigator="true" pattern="dd/MM/yyyy" showOn="button" value="#{cc.attrs.targetValue}" styleClass="#{cc.attrs.styleClass}">
<f:convertDateTime type="date" dateStyle="short" pattern="dd/MM/yyyy"/>
<f:ajax event="blur" execute="#this" render="#this" />
</p:calendar>
</cc:implementation>
</html>
And I´m using this on my form, normally:
<p:outputLabel for="inputInicial:dataInicial" value="#{msg['entity.dataInicial']}" />
<po:inputData id="inputInicial" targetValue="#{acaoController.entity.dataInicial}" fieldId="dataInicial"/>
<p:outputLabel for="inputFinal:dataFinal" value="#{msg['entity.dataFinal']}" />
<po:inputData id="inputFinal" targetValue="#{acaoController.entity.dataFinal}" fieldId="dataFinal" />
And, it works fine when I click to add a new entity... I click on save, and it saves as expected.
When I click to edit an existing entity, and click on save button... This errors occurs:
SEVERE: Servlet.service() for servlet [facesServlet] in context with path [/ProjetoOlimpio] threw exception [javax.el.ELException: /resources/olimpio/inputData.xhtml #18,238 value="#{cc.attrs.targetValue}": Cannot convert 30/12/12 21:00 of type class java.util.Date to class java.sql.Date] with root cause
javax.el.ELException: /resources/olimpio/inputData.xhtml #18,238 value="#{cc.attrs.targetValue}": Cannot convert 30/12/12 21:00 of type class java.util.Date to class java.sql.Date
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:139)
at javax.faces.component.UIInput.updateModel(UIInput.java:818)
at javax.faces.component.UIInput.processUpdates(UIInput.java:735)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIForm.processUpdates(UIForm.java:281)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at org.primefaces.component.layout.Layout.processUpdates(Layout.java:252)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIComponentBase.processUpdates(UIComponentBase.java:1242)
at javax.faces.component.UIViewRoot.processUpdates(UIViewRoot.java:1231)
at com.sun.faces.lifecycle.UpdateModelValuesPhase.execute(UpdateModelValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
My model uses java.util.Date class of course.
import java.util.Date;
[...]
#Column(name = "data_inicial")
#Temporal(TemporalType.DATE)
private Date dataInicial;
#Column(name = "data_final")
#Temporal(TemporalType.DATE)
private Date dataFinal;
I am using Spring Data to persist!
It is hard to understand...
Why does it work on save (not on update) ?
Why does it show the selected Date correctly on the view after I click to edit the entity?
Here some info about my enviroment:
INFO: Starting Servlet Engine: Apache Tomcat/7.0.12
INFO: Initializing Mojarra 2.1.10
INFO: Running on PrimeFaces 3.4.2
INFO: Running on PrimeFaces Extensions 0.6.1
**EDIT
1 - As I said on the comments: the problem is with the composite component, if I put the p:calendar directly on the form it works. So I´ll edit the code snippet of the CC to the whole thing! :)
Notice that I have a type="java.sql.Date" That was added because I was testing. Originally it had no type attribute. I also tested with type="java.util.Date.
There is workaround without changing hibernate model.
I prefer this way because all changes are in jsf layer.
You can use binding in composite component.
Next code is example with rich:calendar (which uses java.util.Date)
...
<cc:interface componentType="CalendarComponent">
...
</cc:interface>
<cc:implementation>
...
<rich:calendar value="#{cc.attrs.value}" binding="#{cc.attrs.calendar}" />
...
</cc:implementation>
...
and in CalendarComponent:
import java.util.Date;
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import org.richfaces.component.UICalendar;
#FacesComponent(value = "CalendarComponent")
public class CalendarComponent extends UINamingContainer {
#Override
public void processUpdates(FacesContext context) {
Object o = calendar.getValue();
if (o instanceof Date) {
Date d = (Date) o;
//this ensures type changing
calendar.setValue(new java.sql.Date(d.getTime()));
}
super.processUpdates(context);
}
private UICalendar calendar;
public UICalendar getCalendar() {
return calendar;
}
public void setCalendar(UICalendar calendar) {
this.calendar = calendar;
}
}

Entity Framework - Id of loaded entity not being assigned

I have the following POCO class:
public class Person : Entity
{
public string FirstName { get; set; }
public string MiddleName1 { get; set; }
public string MiddleName2 { get; set; }
public string LastName { get; set; }
public byte? DayOfBirth { get; set; }
public byte? MonthOfBirth { get; set; }
public Int16? YearOfBirth { get; set; }
public string MobileNumber { get; set; }
}
public abstract class Entity
{
public int Id { get; set; }
}
Here is the corresponding edmx xml:
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
<edmx:StorageModels>
<Schema Namespace="EntityFramework.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
<EntityContainer Name="EntityFrameworkStoreContainer">
<EntitySet Name="People" EntityType="EntityFramework.Store.People" store:Type="Tables" Schema="dbo" />
</EntityContainer>
<EntityType Name="People">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" Nullable="false" />
<Property Name="FirstName" Type="nvarchar" Nullable="false" MaxLength="50" />
<Property Name="MiddleName1" Type="nvarchar" MaxLength="50" />
<Property Name="MiddleName2" Type="nvarchar" MaxLength="50" />
<Property Name="LastName" Type="nvarchar" Nullable="false" MaxLength="50" />
<Property Name="DayOfBirth" Type="tinyint" />
<Property Name="MonthOfBirth" Type="tinyint" />
<Property Name="YearOfBirth" Type="smallint" />
<Property Name="MobileNumber" Type="varchar" MaxLength="20" />
</EntityType>
</Schema>
</edmx:StorageModels>
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema Namespace="EntityFramework" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
<EntityContainer Name="TheCleavesEntities" annotation:LazyLoadingEnabled="true">
<EntitySet Name="People" EntityType="EntityFramework.Person" />
</EntityContainer>
<EntityType Name="Person">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Int32" Nullable="false" />
<Property Name="FirstName" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="MiddleName1" Type="String" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="MiddleName2" Type="String" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="LastName" Type="String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="DayOfBirth" Type="Byte" Nullable="true" />
<Property Name="MonthOfBirth" Type="Byte" Nullable="true" />
<Property Name="YearOfBirth" Type="Int16" Nullable="true" />
<Property Name="MobileNumber" Type="String" MaxLength="20" Unicode="false" FixedLength="false" />
</EntityType>
</Schema>
</edmx:ConceptualModels>
<!-- C-S mapping content -->
<edmx:Mappings>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs">
<EntityContainerMapping StorageEntityContainer="EntityFrameworkStoreContainer" CdmEntityContainer="TheCleavesEntities">
<EntitySetMapping Name="People"><EntityTypeMapping TypeName="EntityFramework.Person"><MappingFragment StoreEntitySet="People">
<ScalarProperty Name="Id" ColumnName="Id" />
<ScalarProperty Name="FirstName" ColumnName="FirstName" />
<ScalarProperty Name="MiddleName1" ColumnName="MiddleName1" />
<ScalarProperty Name="MiddleName2" ColumnName="MiddleName2" />
<ScalarProperty Name="LastName" ColumnName="LastName" />
<ScalarProperty Name="DayOfBirth" ColumnName="DayOfBirth" />
<ScalarProperty Name="MonthOfBirth" ColumnName="MonthOfBirth" />
<ScalarProperty Name="YearOfBirth" ColumnName="YearOfBirth" />
<ScalarProperty Name="MobileNumber" ColumnName="MobileNumber" />
</MappingFragment></EntityTypeMapping></EntitySetMapping>
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
</edmx:Runtime>
<!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
<Designer xmlns="http://schemas.microsoft.com/ado/2008/10/edmx">
<Connection>
<DesignerInfoPropertySet>
<DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
</DesignerInfoPropertySet>
</Connection>
<Options>
<DesignerInfoPropertySet>
<DesignerProperty Name="ValidateOnBuild" Value="true" />
<DesignerProperty Name="EnablePluralization" Value="True" />
<DesignerProperty Name="IncludeForeignKeysInModel" Value="False" />
</DesignerInfoPropertySet>
</Options>
<!-- Diagram content (shape and connector positions) -->
<Diagrams>
<Diagram Name="TheCleaves">
<EntityTypeShape EntityType="EntityFramework.Person" Width="1.5" PointX="0.75" PointY="0.75" Height="2.7494921874999996" IsExpanded="true" />
</Diagram>
</Diagrams>
</Designer>
</edmx:Edmx>
When I load up an entity (there's only one row in the database at present) with the code:
IEnumerable<Person> people = context.People.Where(x => true);
I'm finding that the Id property of the returned Person object is 0 (it's 1 in the database). Anyone have any idea why it appears not to be set?
Thanks
Ok it is not problem with inheritance as I initially thought - the inheritance will work. This is most probably combination of two problems:
Id is generated in the database but EF doesn't know about them. Both SSDL and CSDL part of EDMX should define Id with StoreGeneratedPattern.Identity. This will force EF to reload Id when entity is inserted.
I believe you are using same context instance for saving entity and calling the query. Now you meet identity map pattern. Despite the data retrieved from the query EF will use instance internally stored in its per-context cache. Because of the first problem the cached instance has Id with default int value = 0.

does Entity framework support user defined functions as scalar properties

I would like to include the value of a scalar function as a read-only property of an entity, since that I could include that value in a filter, is such a thing possible?
The solution is to add a DefiningQuery like in the following sample:
<!-- SSDL content -->
<EntitySet Name="Emp" EntityType="TestModel.Store.Emp" >
<DefiningQuery>
SELECT EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO, dbo.MyFunc(DEPTNO) AS DNAME FROM EMP
</DefiningQuery>
</EntitySet>
<EntityType Name="Emp">
<Key>
<PropertyRef Name="EMPNO" />
</Key>
<Property Name="EMPNO" Type="int" Nullable="false" />
...
<Property Name="DNAME" Type="varchar" MaxLength ="20" />
</EntityType>
...
<!-- CSDL content -->
...
<EntityType Name="Emp">
<Key>
<PropertyRef Name="EMPNO" />
</Key>
<Property Name="EMPNO" Type="Int32" Nullable="false" />
...
<Property Name="DNAME" Type="String" MaxLength="20" Unicode="false" FixedLength="false" />
</EntityType>
<!-- C-S mapping content -->
...
<ScalarProperty Name="EMPNO" ColumnName="EMPNO" />
...
<ScalarProperty Name="DNAME" ColumnName="DNAME" />
...
The usage example:
using(TestEntities4 db = new TestEntities4()) {
var q = from e in db.Emp where e.DNAME == "RESEARCH" select e;
}
In EF4 you can define a partial class of the same name as your Entity Framework class in the same namespace and add read-only properties to that. I've just done that to expose the description of a connected Entity object as a read-only property of the original object.
namespace same.as.the.data.model
{
public partial class Order
{
public string CustomerName
{
get { return Customer.Name; }
}
}
}

Resources