in JAXB, if annotations were not provided, the element names will be derived from the property names not fields, but what about attributes in this case? is there any default behavior for writing out attributes back to the XML file?
1) If annotations were not provided:
Every public getter/setter pair and every public field will be
automatically bound to XML, unless annotated by {#link XmlTransient}
For example
public class Cat
{
public String name = "tomcat";
private String nick = "catalina";
public int getAge() { return 5; }
public void setAge(int age) {}
}
after
JAXB.marshal(cat, System.out);
output is
<cat>
<name>tomcat</name>
<age>5</age>
</cat>
2) What about XML attributes? XML attribute is named like field or getter/setter pair and placed in the root node
for example
#XmlAccessorType(XmlAccessType.FIELD)
public class Cat
{
String name = "tomcat";
#XmlAttribute
String nick = "catalina";
#XmlAttribute
String home = "java.home";
int age = 5;
}
output is
<cat home="java.home" nick="catalina">
<name>tomcat</name>
<age>5</age>
</cat>
Related
I want to create a custom lightning component to create new Case records and need to use fieldset to include fields in component. Need to use this only for one object. I never used fieldsets so dont have any idea on it. It would be really great if you can share some sample code or any link for the same.
You can use this utility class
This is the wrapper class to hold the meta info about the fields
public with sharing class DataTableColumns {
#AuraEnabled
public String label {get;set;}
#AuraEnabled
public String fieldName {get;set;}
#AuraEnabled
public String type {get;set;}
public DataTableColumns(String label, String fieldName, String type){
this.label = label;
this.fieldName = fieldName;
this.type = type;
}
}
Class FieldSetHelper has a method getColumns () this will return the list of DataTableColumns wrapper containing the information about the filedset columns
public with sharing class FieldSetHelper {
/*
#param String strObjectName : required. Object name to get the required filed set
#param String strFieldSetName : required. FieldSet name
#return List<DataTableColumns> list of columns in the specified fieldSet
*/
public static List<DataTableColumns> getColumns (String strObjectName, String strFieldSetName) {
Schema.SObjectType SObjectTypeObj = Schema.getGlobalDescribe().get(strObjectName);
Schema.DescribeSObjectResult DescribeSObjectResultObj = SObjectTypeObj.getDescribe();
Schema.FieldSet fieldSetObj = DescribeSObjectResultObj.FieldSets.getMap().get(strFieldSetName);
List<DataTableColumns> lstDataColumns = new List<DataTableColumns>();
for( Schema.FieldSetMember eachFieldSetMember : fieldSetObj.getFields() ){
String dataType =
String.valueOf(eachFieldSetMember.getType()).toLowerCase();
DataTableColumns datacolumns = new DataTableColumns(
String.valueOf(eachFieldSetMember.getLabel()) ,
String.valueOf(eachFieldSetMember.getFieldPath()),
String.valueOf(eachFieldSetMember.getType()).toLowerCase() );
lstDataColumns.add(datacolumns);
}
return lstDataColumns;
}
}
After you getting all those field set information the create lightning component dynamically
I have the below JSON code that needs to be parsed. I'm using the corresponding JAX-RS models. The problem is that the paymillClient object is null. If I add currency as a string inside the PaymillSubscription object, it returns EUR value, not null. So there appears to be a problem with the PaymillClient object, not plain strings. Could there be a limit to the number of nested objects for parsing ? Ex, max 2 nested objects. So because there are 3 in my case, it doesn't work.
Unfortunately, I cannot change the JSON code that needs to be parsed at all. I just need to make it work with the JAX-RS implementation.
{
"event":{
"event_type":"subscription.succeeded",
"event_resource":{
"subscription":{
"id":"sub_29f144a3bc32c71f96e2",
"offer":{ },
"livemode":false,
"amount":200,
"temp_amount":null,
"currency":"EUR",
"name":"Monthly subscription",
"interval":"1 MONTH",
"trial_start":null,
"trial_end":null,
"period_of_validity":null,
"end_of_period":null,
"next_capture_at":1428939744,
"created_at":1426264944,
"updated_at":1426264944,
"canceled_at":null,
"payment":{ },
"app_id":null,
"is_canceled":false,
"is_deleted":false,
"status":"active",
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
},
"transaction":{ }
},
"created_at":1426264944,
"app_id":null
}
}
PaymillEventContainer:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventContainer
{
private PaymillEvent event;
}
PaymillEvent:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEvent
{
#XmlElement(name = "event_type") #DocumentationExample(value = "subscription.succeeded") private String eventType;
#XmlElement(name = "event_resource") private PaymillEventResource eventResource;
}
PaymillEventResource:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventResource
{
private PaymillClient client;
private PaymillOffer offer;
private PaymillSubscription subscription;
}
PaymillSubscription:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillSubscription
{
private PaymillClient client;
private PaymillOffer offer;
}
PaymillClient:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillClient
{
#DocumentationExample(value = "client_c0c24aa7f97e1b8ed15d") private String id;
}
API endpoint code:
public Response postSubscriptionSucceeded(PaymillEventContainer paymillEventContainer)
{
PaymillEvent paymillEvent = paymillEventContainer.getPaymillEvent();
PaymillEventResource paymillEventResource = paymillEvent.getEventResource();
PaymillSubscription paymillSubscription = paymillEventResource.getSubscription();
PaymillClient paymillClient = paymillSubscription.getPaymillClient();
PaymillOffer paymillOffer = paymillSubscription.getPaymillOffer();
String clientId = paymillClient.getId(); // NullPointerException
}
Ok. I tried to run your code on your machine and also received null (note, that I'm using MOXy to unmarshall JSON). Then, I tried to experiment with it a little and found really funny things:
1. If you will remove all null-valued fields from your JSON, all works just perfect.
2. If you will add another field to PaymillSubscription. I added private Test test, where Test is:
#XmlAccessorType(XmlAccessType.FIELD)
public class Test {
private String id;
}
And will send this "test" object between last null-valued field in subscription object and "client" field:
"test":{"id":"sadas"},
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
Then "test" would be null, but "client" will be parsed as expected.
3. If you will add all null-valued objects into model (I mean, create respective fields in PaymillSubscription class) all works just perfect.
It seems, that by default JAXB specification doesn't allow JSON with unrecognized fields, but MOXy still tries to parse it (and sometimes produces errors).
I cant unmarshall xml because don't understand how to annotate object class in the another object. Please help.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<ODZ xmlns="http://www.company.com/1.0" >
<Data DataID="ZZZ">
<UserData UserKey="user_001">
<UserEvent>...</UserEvent>
</UserData>
</Data>
</ODZ>
Container classes:
I. First level with link to the second (ODZ -> Data).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "ODZ", namespace = "http://www.company.com/1.0")
public class ODZContainer {
private ImportContainer importContainer;
#XmlElement (name = "Data", type=ImportContainer.class)
public ImportContainer getImportContainer() {
return importContainer;
}
}
II. Second level with link to the third level(Data -> UserData).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "Data")
public class ImportContainer {
private String DataID;
private ArrayList<UserDataBean> userDataBean;
#XmlElement (name = "UserData", type=UserDataBean.class)
public ArrayList<UserDataBean> getUserDataBean() {
return userDataBean;
}
#XmlAttribute(name = "DataID")
public String getDataID() {
return DataID;
}
}
III. Third level with link to the fourth level(UserData-> UserEvent).
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "UserData")
public class UserDataBean {
private ArrayList<UserEventBean> userEventData;
private String userEventID;
#XmlAttribute(name = "UserKey")
public String getUserEventID() {
return userEventID;
}
#XmlElement (name = "UserEvent", type=UserEventBean.class)
public ArrayList<UserEventBean> getUserEventBean() {
return userEventData;
}
}
The namespace qualification in your JAXB metadata does not match your XML. You can use the package level #XmlSchema annotation to specify the namespace qualification for your model.
#XmlSchema(
namespace = "http://www.company.com/1.0",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information on JAXB and Namespaces
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Notes About Your Metadata
Since the type of the ArrayList is already specified, you don't need to specify it via the #XmlElement annotation. It doesn't hurt, but its not necessary.
#XmlElement (name = "UserData", type=UserDataBean.class)
public ArrayList<UserDataBean> getUserDataBean() {
return userDataBean;
}
#XmlAccessorType(XmlAccessType.NONE) means that nothing is mapped unless it is explicitly annotated. This may or not be what you want. You may find the following article useful:
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
I have a Object with two fields "name" and "address". JAXB ignores the empty elements while transforming the object into XMl.
For ex: if I have name="xyz" and address=null then out will be
<name>xyz</name>
but what I want as an output as
<name>xyz</name>
<address></address>
I have seen the option #XmlElement(nillable="true") but this gives the output as
<name>xyz</name>
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
Please help me getting the desired output.
Thanks in advance.
A JAXB (JSR-222) implementation will output an empty String "" value as an empty element. You can set the address property to this to get the desired effect.
UPDATE #1
I have updated my question. Basically the address element is NULL. Is
this solution applicable to that as well?
You could leverage Marshal Event Callbacks to adjust the value of address.
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String name;
private String address;
private void beforeMarshal(Marshaller marshaller) {
if(null == address) {
address = "";
}
}
private void afterMarshal(Marshaller marshaller) {
if("".equals(address)) {
address = null;
}
}
}
UPDATE #2
The only concern is that if I have 10 fields in the class I will have
to write if for all the fields. Is there any other solution?
If you use EclipseLink MOXy as your JAXB provider (I'm the MOXy lead), then you could use an XmlAdapter for this use case.
XmlAdapter (StringAdapter)
package forum14691333;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String string) throws Exception {
if(null == string) {
return "";
}
return string;
}
#Override
public String unmarshal(String string) throws Exception {
if("".equals(string)) {
return null;
}
return string;
}
}
package-info
Then if you specify it at the package level it will apply to all mapped fields/properties of type String within that package.
#XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
package forum14691333;
import javax.xml.bind.annotation.adapters.*;
For More Information
http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If you use EclipseLink MOXy as your JAXB provider then you could use
#XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
#XmlElement(name = "address", nillable = true)
private String address;
By using this way, you don't have to write adapter for all the fields
Simply set an empty string default value on the field.
#XmlElement(required="true")
private String address = "";
and you will get
<address></address>
I have the following model:
Public Class MyModel
Public Property MyModelId As Integer
Public Property Description As String
Public Property AnotherProperty As String
End Class
Is there a method to get a property name of the Model as a string representation like the following code?
Dim propertyName as String = GetPropertyNameAsStringMethod(MyModel.Description)
So the propertyName variable has "Description" as value.
Check the Darin Dimitrov' answer on this SO thread - Reflection - get property name.
class Foo
{
public string Bar { get; set; }
}
class Program
{
static void Main()
{
var result = Get<Foo, string>(x => x.Bar);
Console.WriteLine(result);
}
static string Get<T, TResult>(Expression<Func<T, TResult>> expression)
{
var me = expression.Body as MemberExpression;
if (me != null)
{
return me.Member.Name;
}
return null;
}
}
Hope this help..
Here is a helper extension method you can use for any property:
public static class ReflectionExtensions
{
public static string PropertyName<T>(this T owner,
Expression<Func<T, object>> expression) where T : class
{
if (owner == null) throw new ArgumentNullException("owner");
var memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
}
However, this will only work on instances of a class. You can write a similar extension method that will operate directly on the type instead.
You need to do it using reflection.
There are already loads of posts on stack overflow like this:
How to get current property name via reflection?
Reflection - get property name
Get string name of property using reflection
Reflection - get property name
I believe that the answer will be along the lines of:
string prop = "name";
PropertyInfo pi = myObject.GetType().GetProperty(prop);
Create an extension method and then use it where needed.
Private Shared Function GetPropertyName(Of T)(exp As Expression(Of Func(Of T))) As String
Return (DirectCast(exp.Body, MemberExpression).Member).Name
End Function
have a look at this post as well.
I have solved this issue editing a bit #NiranjanKala's source example,
converting the code in vb.Net like this
<System.Runtime.CompilerServices.Extension()> _
Public Function GetPropertyName(Of T, TResult)(expression As Expression(Of Func(Of T, TResult))) As String
Dim [me] = TryCast(expression.Body, MemberExpression)
If [me] IsNot Nothing Then
Return [me].Member.Name
End If
Return Nothing
End Function
Then I am able to call the extension like this
Dim propertyName as String = GetPropertyName(Of MyModel, String)(Function(x) x.Description)
Then propertyName variable has "Description" as string value.