With Eclipselink Moxy How do I map xml content to a name different to value? - eclipselink

In my Xml I have:
<alias-list>
<alias sort-name="Afghan">Afghany</alias>
</alias-list>
The json is output as
"aliases" [ {
"sort-name" : "Afghan",
value : "Afghany"
} ]
but I want it to be:
"aliases" [ {
"sort-name" : "Afghan",
name : "Afghany"
} ]
So I know how to use oxml.xml to rename an attribute but in this case there is no attribute so unsure how to proceed.

There is a property you can set to override the default "value" for MOXy's JSON marshalling. This property is set per context (or can be set per Marshaller) not per mapping so "myValueWrapper" will now be used instead of the default "value" for all mappings where it's needed.
Map<String, Object> props = new HashMap<String, Object>();
props.put(JAXBContextProperties.JSON_VALUE_WRAPPER, "myValueWrapper");
JAXBContext context = JAXBContext.newInstance(myClasses, props);
Alternatively you could handles this on a per attribute basis by creating different JAXBContexts that make use of external bindings files which can specify different behavior. Create a bindings file for XML that treats name as having an #XmlValue annotation and create a bindings file for JSON that treats name as having an #XmlElement annotation.
Example xmlbindings.xml
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="mypackage.test">
<java-types>
<java-type name="Alias">
<java-attributes>
<xml-value java-attribute="name"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Example jsonbindings.xml
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="mypackage.test">
<java-types>
<java-type name="Alias">
<java-attributes>
<xml-element java-attribute="name" name="name"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
To create the JAXBContext with a bindings file you do the following:
Map<String, Object> props = new HashMap<String, Object>();
StreamSource ss = new StreamSource(new File("pathtobindings/xmlbindings.xml")); props.put(JAXBContextProperties.OXM_METADATA_SOURCE, ss);
JAXBContext contextWithXMLBindings = JAXBContext.newInstance(myClasses, props);

Related

Use of SerializationFeature.WRAP_ROOT_VALUE ahead of xmlRootElement

I just want to understand what is the use of SerializationFeature.WRAP_ROOT_VALUE.
I have actually tried disabling the SerializationFeature.WRAP_ROOT_VALUE and for the class I have annotated with xmlRootElement. Here in this case after disabling the SerializationFeature.WRAP_ROOT_VALUE still after serializing I am getting the root value. To just avoid the root value I have to use the xmlType.
So trying to understand then what is the use of SerializationFeature.WRAP_ROOT_VALUE?
Sample code which I have tried
#XmlRootElement(name="person")
Public class Person {
#XmlElement(name = "insert")
private int insert;
#XmlElement(name = "update")
private int update;
}
The above is the POJO class which I was trying to serialize and also I have used
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
So with the above code the output is
"person" {
"insert" : 1,
"update" : 0
}
In the same case if I try to change the xmlRootElement to XmlType in Person class the output is
{
"insert" : 1,
"update" : 0
}
So I am confused like what is the use of SerializationFeature.WRAP_ROOT_VALUE if it is not giving the expected output?
I am using the Jackson version of 2.9.6
After digging more into this found that with the help of CXF I was able to solve this by adding small config in applicationcontext.xml file
<bean class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
<property name="dropRootElement" value="true" />
</bean>

Send MessageProperties [priority=anyInteger] while publishing message in RabbitMQ

we are using rabbit MQ and Spring Integration in our project. Every Message has a deliver mode, header, properties, and payload part.
We want to add properties i.e) priority with value 2(any integer) , payload with "test message 3" and publish the message to the queue named OES. please see screen shot.
How to add the messageproperties i.e) priority =2(or any value) in the below outbound-channel-adapter(Spring Integration). I know we can add "headers" by adding into "mapped-request-headers" but i would like to add the properties. There are no properties defined for the MessageProperties in "outbound-channel-adapter". Is there a way to overcome this issue.
We have no issues with payload, it is going already. we want to add only the MessageProperties with priority=2(any value). how to add that in the outbound-channel-adapter(no need of hardcoding, should be generic)?
<!-- the mapped-request-headers should be symmetric with
the list on the consumer side defined in consumerbeans.consumerHeaderMapper() -->
<int-amqp:outbound-channel-adapter id="publishingAmqpAdapter"
channel="producer-processed-event-channel"
amqp-template="amqpPublishingTemplate"
exchange-name="events_forwarding_exchange"
routing-key-expression="headers['routing-path']"
mapped-request-headers="X-CallerIdentity,routing-path,content-type,route_to*,event-type,compression-state,STANDARD_REQUEST_HEADERS"
/>
Other configuration:
<!-- chain routes and transforms the ApplicationEvent into a json string -->
<int:chain id="routingAndTransforming"
input-channel="producer-inbound-event-channel"
output-channel="producer-routed-event-channel">
<int:transformer ref="outboundMessageTracker"/>
<int:transformer ref="messagePropertiesTransformer"/>
<int:transformer ref="eventRouter"/>
<int:transformer ref="eventToJsonTransformer"/>
</int:chain>
<int:transformer id="messagePayloadCompressor"
input-channel="compress-message-payload"
output-channel="producer-processed-event-channel"
ref="payloadCompressor"/>
#Configuration("amqpProducerBeans")
#ImportResource(value = "classpath:com/apple/store/platform/events/si/event-producer-flow.xml")
public class AmqpProducerBeans {
#Bean(name = { "amqpPublishingTemplate" })
public AmqpTemplate amqpTemplate() {
logger.debug("creating amqp publishing template");
RabbitTemplate rabbitTemplate = new RabbitTemplate(producerConnectionFactory());
SimpleMessageConverter converter = new SimpleMessageConverter();
// following needed for retry logic
converter.setCreateMessageIds(true);
rabbitTemplate.setMessageConverter(converter);
return rabbitTemplate;
}
/*Other code commented */
}
Other Code:
import org.springframework.integration.Message;
import org.springframework.integration.annotation.Transformer;
import org.springframework.integration.message.GenericMessage;
public class PayloadCompressor {
#Transformer
public Message<byte[]> compress(Message<String> message){
/* some code commented */
Map<String, Object> headers = new HashMap<String, Object>();
headers.putAll(message.getHeaders());
headers.remove("compression-state");
headers.put("compression-state", CompressionState.COMPRESSED);
Message<byte[]> compressedMessage = new GenericMessage<byte[]>(compressedPayload, headers);
return compressedMessage;
}
If we are not using spring integration, then we can use channel.basicPublish below way and send the MessageProperties.
ConnectionFactory factory = new ConnectionFactory();
factory.setVirtualHost("/");
factory.setHost("10.102.175.30");
factory.setUsername("rahul");
factory.setPassword("rahul");
factory.setPort(5672);
Connection connection = factory.newConnection();
System.out.println("got connection "+connection);
Channel channel = connection.createChannel();
MessageProperties msgproperties= new MessageProperties() ;
MessageProperties.BASIC.setPriority(3);
// set Messageproperties with priority
    String exchangeName = "HeaderExchange";
      String routingKey = "testkey";
      //routingkey
      byte[] messageBodyBytes = "Message having priority value 3".getBytes();
      channel.basicPublish(exchangeName,
                           routingKey,
                           true,
                           msgproperties.BASIC,
                           messageBodyBytes);
Please let me know if you need more details.
Properties are already mapped automatically - see the header mapper.
Simply use a <header-enricher/> to set the appropriate header and it will be mapped to the correct property. In the case of priority, the constant is here for the amqp-specific header constants, see here.

ReadAsAsync<T>,Expecting element from namespace 'http://schemas.datacontract.org/2004/07/",Encountered 'Element' with name 'workflow', namespace ''

I am trying to consume a REST API to Get data by httpclient, encountered a parsing problem ,{"Error in line 1 position 95. Expecting element 'workflow' from namespace 'http://schemas.datacontract.org/2004/07/'.. Encountered 'Element' with name 'workflow', namespace ''. "}
the client code is
string baseUri = "/rest/workflows/";
client = CreateClient(baseUri);
HttpRequestMessage request = CreateRequest(baseUri);
var task = client.SendAsync(request);
HttpResponseMessage response = task.Result;
response.EnsureSuccessStatusCode();
response.Content.ReadAsAsync<collection>().ContinueWith(wf =>
{
Console.WriteLine(wf.Result.workflow.Length);
});
the data classes
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/Atom", IsNullable = false)]
public partial class collection
{
private workflow[] workflowField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("workflow", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public workflow[] workflow
{
get
{
return this.workflowField;
}
set
{
this.workflowField = value;
}
}
}
and the response xml file is in this format
<collection xmlns:ns2="http://www.w3.org/2005/Atom">
<workflow uuid="5ffbde8c-c430-4851-9c83-164c102a4d68">
<name>Remove a Volume</name>
<categories>
<category>Decommissioning</category>
</categories>
</workflow>
</collection>
I can get the string by using response.Content.ReadAsStringAsync() and save it to xml file, then ,i deserilize it to collection,can succeed ,but need and a default namespace to the serizliazer
XmlSerializer serializer = new XmlSerializer(typeof(collection), "xmlns:ns2=\"http://www.w3.org/2005/Atom\"");
c = serializer.Deserialize(stream) as collection;
anyone can help on this
You should not touch the generated file from xsd.exe tool.
Just explicitly set that you want to use the XmlSerializer instead of the DataContractSerializer used by default with XmlMediaTypeFormatter by setting UseXmlSerializer = true.
So you must create a specific type formatter like this :
var formatters = new List<MediaTypeFormatter>() {
new XmlMediaTypeFormatter(){ UseXmlSerializer = true } };
And use it as a parameter of the ReadAsAsync method :
private async Task<T> ReadAsync<T>(HttpResponseMessage response)
=> await response.Content.ReadAsAsync<T>(formatters);
Your namespaces do not match; your xml declares a namespace alias (ns2) for the atom address, but the namespace of the collection element is still empty, since it doesn't use that alias (it is not ns2:collection). Either the xml is wrong or the code is. If the xml cannot be changed, then simply set the namespace on the [XmlRoot(...)] to be the empty string. If the C# is correct and the xml is wrong, then make it the namespace instead of an alias:
<collection xmlns="http://www.w3.org/2005/Atom">
<workflow uuid="5ffbde8c-c430-4851-9c83-164c102a4d68">
<name>Remove a Volume</name>
<categories>
<category>Decommissioning</category>
</categories>
</workflow>
</collection>
or identically:
<ns2:collection xmlns:ns2="http://www.w3.org/2005/Atom">
<workflow uuid="5ffbde8c-c430-4851-9c83-164c102a4d68">
<name>Remove a Volume</name>
<categories>
<category>Decommissioning</category>
</categories>
</workflow>
</ns2:collection>
I had the exact same issue when reading data from my web api. What solved the issue for me is to decorate the class in the client with the [DataContract(Namespace="namespacefromyourwebapi")] attribute and for each property in your class decorate it with the [DataMember] attribute.

How to retrieve invalid references from Velocity Engine?

I am wondering if there is a way to retrieve a list of invalid references in Velocity after calling VelocityEngine.evaluate.
Velocity Eventhandler has some nice information about creating an AppSpecificInvalidReferenceEventHandler which I have used in the VelocityEngine as follows.
<bean id="templateVelocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<props>
<prop key="resource.loader">class</prop>
<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
<prop key="class.resource.loader.cache">true</prop>
<prop key="eventhandler.invalidreferences.class">xyz.util.AppSpecificInvalidReferenceEventHandler,org.apache.velocity.app.event.implement.ReportInvalidReferences</prop>
</props>
</property>
</bean>
After velocity's evaluate call, I see the log statements showing that AppSpecificInvalidReferenceEventHandler is working, but I can't see how to retrieve that class and it's List of InvalidReferenceInfo if I declare the eventhandler.invalidreferences.class in the Spring context as above.
Populating and evaluating the template looks like the following :-
VelocityContext context = new VelocityContext();
StringWriter bodyWriter = new StringWriter();
context.put("body", "some body text!");
boolean result = templateVelocityEngine.evaluate(context, bodyWriter, "logTag", "template ${body} text here loaded from a file");
So I would like to do something like the following (except ec.getInvalidReferenceEventHandlers() is null)
EventCartridge ec = context.getEventCartridge();
Iterator it = ec.getInvalidReferenceEventHandlers();
while (it.hasNext()) {
Object obj = it.next();
if (obj instanceof ReportInvalidReferences) {
AppSpecificInvalidReferenceEventHandler handler = (AppSpecificInvalidReferenceEventHandler) obj;
List invalidRefs = handler.getInvalidReferences();
if (!invalidRefs.isEmpty()) {
// process the list of invalid references here
}
}
}
The only way around this I've found so far is to not declare eventhandler.invalidreferences.class in the Spring bean i.e. instead I would do the following
ReportInvalidReferences reporter = new AppSpecificInvalidReferenceEventHandler();
EventCartridge ec = new EventCartridge();
ec.addEventHandler(reporter);
ec.attachToContext(context);
VelocityContext context = new VelocityContext();
StringWriter bodyWriter = new StringWriter();
context.put("body", "some body text!");
boolean result = templateVelocityEngine.evaluate(context, bodyWriter, "logTag", "template ${body} text here loaded from a file");
With the additional pre Velocity evaluate setup code above (and commenting the eventhandler.invalidreferences.class in the Spring bean), I can then call
ec.getInvalidReferenceEventHandlers();
And I get back the AppSpecificInvalidReferenceEventHandler in the Iterator returned...

ejb3.1 #Startup.. #Singleton .. #PostConstruct read from XML the Objects

I need to initialize a set of static String values stored in an XML files [ I know this is against the EJB spec ]
as shown below since the over all Idea is to not hardcore within EJB's the JNDI info
Utils.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="jndidb">java:jdbc/MYSQLDB10</entry>
<entry key="jndimdbque">java:jms/QueueName/remote</entry>
<entry key="jndi1">DBConnections/remote</entry>
<entry key="jndi2">AddressBean/remote</entry>
</properties>
The Onload of ejbserver startup code is as follows ...
inpstrem = clds.getClassLoaders(flename) Reads the Util.xml and stores the same in Hashtable key value pare....
package com.ejb.utils;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Singleton
#Startup
public class StartupUtils {
private final String INITFILENAME = "/System/Config/Utils.xml";
private static Hashtable HTINITFLENME=null,HTERRINITFLENME=null,HTCMMNFLENME=null;
public StartupUtils() {
HTINITFLENME = new Hashtable();
HTERRINITFLENME = new Hashtable();
}
public void printAll(Hashtable htcmmnflenme){
Enumeration ENUMK = null, VALS = null;
String KEY = "", VALUE = "";
ENUMK = htcmmnflenme.keys();
while (ENUMK.hasMoreElements()) {
KEY = null;VALUE = null;
KEY = (ENUMK.nextElement().toString().trim());
VALUE = htcmmnflenme.get(KEY).toString().trim();
InitLogDisplay(KEY + " :::: " + VALUE);
}
}
public static void InitLogDisplay(String Datadisplay){
System.out.println(Datadisplay);
}
public Hashtable getDataProp(String flename){
Map htData = null;
InputStream inpstrem = null;
ClassLoaders clds = null;
Enumeration enumk = null, vals = null;
String key = "", value = "";
Properties props = null;
Hashtable htx = null;
try {
clds = new ClassLoaders();
inpstrem = clds.getClassLoaders(flename);
props = new Properties();
props.loadFromXML(inpstrem);
enumk = props.keys();
vals = props.elements();
htData = new HashMap();
htData = new TreeMap();
while (enumk.hasMoreElements()) {
key = (enumk.nextElement().toString().trim());
value = (vals.nextElement().toString().trim());
htData.put(key,value);
}
clds = null;
props = null;
inpstrem.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
key = ""; value = "";
enumk = null;vals = null;
clds=null;
props=null;
}
htx = new Hashtable();
htx.putAll(htData);
return htx;
}
public void setUtilsPropDetails(){
HTINITFLENME = getDataProp(INITFILENAME);
this.printAll(HTINITFLENME);
}
public static Hashtable getUtilsPropDetails(){
return HTINITFLENME;
}
#PostConstruct
public void startOnstartup(){
this.setUtilsPropDetails();
this.printAll();
}
#PreDestroy
public void startOnshutdown(){
try {
this.finalize();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
On startup of EJB server "this.printAll(HTINITFLENME);" prints the key values of the XML file hoever If an external Call is made via any other EJB's to the method "getUtilsPropDetails()" does not return the key values....
Am i doing something wrong ??????
Have you considered using the deployment descriptor and having the container do this work for you?
There are of course <resource-ref>, <resource-env-ref>, <ejb-ref> and <env-entry> elements to cover externally configuring which things should be made available to the bean for lookup. For example:
<resource-ref>
<res-ref-name>db</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<mapped-name>java:jdbc/MYSQLDB10</mapped-name>
</resource-ref>
I'm not sure how your vendor handles mapped-name (that particular element is vendor specific), but there will be an equivalent syntax to specify the datasource you want.
The singleton can then lookup java:comp/env/db and return the datasource to other EJBs.
If you are in a compliant Java EE 6 server, then you can change the name to <res-ref-name>java:app/db</res-ref-name> and then anyone in the app can lookup the datasource without the need to get it from the singleton. Global JNDI is a standard feature of Java EE 6 and designed for exactly this.
You can put those elements in the ejb-jar.xml, web.xml or application.xml. Putting them in the application.xml will make the one entry available to the entire application and give you one place to maintain everything.
Global resources can also be injected via:
#Resource(name="java:app/db")
DataSource dataSource;
If for some reason you didn't want to use those, at the very least you could use the <env-entry> element to externalize the strings.
EDIT
See this other answer for a much more complete description of JNDI as it pertains to simple types. This of course can be done where the name/value pairs are not simple types and instead are more complex types like DataSource and Topic or Queue
For example:
<resource-ref>
<res-ref-name>myDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>
<resource-ref>
<res-ref-name>myJmsConnectionFactory</res-ref-name>
<res-type>javax.jms.ConnectionFactory</res-type>
</resource-ref>
<resource-ref>
<res-ref-name>myQueueCF</res-ref-name>
<res-type>javax.jms.QueueConnectionFactory</res-type>
</resource-ref>
<resource-ref>
<res-ref-name>myTopicCF</res-ref-name>
<res-type>javax.jms.TopicConnectionFactory</res-type>
</resource-ref>
<resource-env-ref>
<resource-env-ref-name>myQueue</resource-env-ref-name>
<resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
</resource-env-ref>
<resource-env-ref>
<resource-env-ref-name>myTopic</resource-env-ref-name>
<resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
</resource-env-ref>
<persistence-context-ref>
<persistence-context-ref-name>myEntityManager</persistence-context-ref-name>
<persistence-unit-name>test-unit</persistence-unit-name>
</persistence-context-ref>
<persistence-unit-ref>
<persistence-unit-ref-name>myEntityManagerFactory</persistence-unit-ref-name>
<persistence-unit-name>test-unit</persistence-unit-name>
</persistence-unit-ref>
See the JNDI and simple types answer for look and injection syntax.
I see the name and type, but where's the value?
Configuring what actual things these names refer to has historically been done in a separate vendor specific deployment descriptor, such as sun-ejb-jar.xml or openejb-jar.xml or whatever that vendor requires. The vendor-specific descriptor and the standard ejb-jar.xml descriptor combined provide the guaranteed portability apps require.
The ejb-jar.xml file offering only standard things like being able to say what types of resources the application requires and what names the application has chosen to use to refer to those resources. The vendor-specific descriptor fills the gap of mapping those names to actual resources in the system.
As of EJB 3.0/Java EE 5, we on the spec groups departed from that slightly and added the <mapped-name> element which can be used in the ejb-jar.xml with any of the references shown above, such as <resource-ref>, to the vendor-specific name. Mapped name will never be portable and its value will always be vendor-specific -- if it is supported at all.
That said, <mapped-name> can be convenient in avoiding the need for a separate vendor-specific file and achieves the goal of getting vendors-specific names out of code. After all, the ejb-jar.xml can be edited when moving from one vendor to another and for many people that's good enough.