JAXB xjc: How to generate code for Strings that returns empty if the value is null? - jaxb

Given the following example xsd snippet:
< xs:attribute name="SEGMENT" default="" use="optional" type="xs:string"/ >
when xjc generates the class containing the SEGMENT bean attribute, the following getter is auto-generated:
public String getSEGMENT() {
if (segment == null) {
return "";
} else {
return segment;
}
}
My question is how do you get it do the same for xs:element objects? In other words, given the following xsd snippet:
< xs:element name="NAME" default="" type="xs:string"/ >
I want to know if I can get xjc to generate the following:
public String getNAME() {
if (name == null) {
return "";
} else {
return name;
}
}
How can this be done?

JAXB doesn't generate the same code for an element with default value as it does for an attribute with default value because the XML schema differentiates between element and attribute defaults:
Default values of both attributes and elements are declared using the default attribute, although this attribute has a slightly different consequence in each case. When an attribute is declared with a default value, the value of the attribute is whatever value appears as the attribute's value in an instance document; if the attribute does not appear in the instance document, the schema processor provides the attribute with a value equal to that of the default attribute. Note that default values for attributes only make sense if the attributes themselves are optional, and so it is an error to specify both a default value and anything other than a value of optional for use.
The schema processor treats defaulted elements slightly differently. When an element is declared with a default value, the value of the element is whatever value appears as the element's content in the instance document; if the element appears without any content, the schema processor provides the element with a value equal to that of the default attribute. However, if the element does not appear in the instance document, the schema processor does not provide the element at all. In summary, the differences between element and attribute defaults can be stated as: Default attribute values apply when attributes are missing, and default element values apply when elements are empty.
You can always count on the default value for a missing attribute (from here the special getter) but there is a catch with a missing element value.
Nonetheless, when you unmarshall an instance, the unmarshaller knows how to handle the default value. See here for details:
Element default values and marshalling
Element default values and unmarshalling
XJC won't add the getter code or initialize the fields with the default value, so if you need the "null safe check" you can either add it yourself manually after the code is generated by XJC or try to use some plugin to do it automatically:
JAXB 2 Default Value Plugin
CXF XJC Default Value Plugin

Related

Impex Export: Colon in multivalue attribute is escaped by double backslash - How to remove this behavior?

Hybris: 6.3.0.0-SNAPSHOT (the behavior is the same with 6.3.0.21)
When exporting impex, we noticed a difference when exporting a non-multivalue Type attribute versus exporting a multivalue Type attribute.
When exporting String attribute data without colon, a non-multivalue attribute can be exported as Experts, while a multivalue attribute can be exported as Experts|Hybris.
When exporting Type with String attribute data with colons (e.g. URL), the colon is escaped with a double backslash (for multivalue only). A non-multivalue attribute can be exported as https://experts.hybris.com, while a multivale attribute can be exported as https\://experts.hybris.com if there is only 1 value or as https\://experts.hybris.com|https\://help.hybris.com if there are 2 values.
How can I stop the export from escaping the colon? Is there a method I can override to change this behavior? I would like to change the result to https://experts.hybris.com|https://help.hybris.com or to "https://experts.hybris.com"|"https://help.hybris.com".
Business Case: We want to copy the URL from the exported impex, but the URL contains double backslashes. The exported impex is not meant to be reimported.
Notes #`: The URLs are stored in a collection (e.g. Product.newAttribute, where newAttribute is a collection of custom types which has a String). So, the Impex header looks something like "INSERT_UPDATE Product;newAttribute(data)"
Notes #2: (UPDATE: Didn't work) Currently, I'm checking if it's possible with a CSVCellDecorator; this is for import only.
Notes #3: Currently, I'm checking if it's possible with AbstractSpecialValueTranslator.
For this specific case, I created a new translator, extending AbstractValueTranslator. Then, I implemented the exportValue method, joining the string data (which are URLs), without escaping them.
public String exportValue(final Object value) throws JaloInvalidParameterException
{
String joinedString = "";
if (value instanceof Collection)
{
final Collection valueCollection = (Collection) value;
if (!valueCollection.isEmpty())
{
final ArrayList<CustomType> list = (ArrayList<CustomType>) valueCollection;
final StringJoiner joiner = new StringJoiner("|");
for (final CustomType customType : list)
{
// data is a URL
joiner.add(customType.getData());
}
// value would be something like "https://experts.hybris.com|https://help.hybris.com"
joinedString = joiner.toString();
}
}
return joinedString;
}
Reference:
Customization: https://help.hybris.com/1808/hcd/ef51040168d743879c015b7de232ce40.html
I think that might not be possible, since the colon is used to separate keys for referenced types. As in
...;catalogVersion(catalog(id),version);...
...;myCatalog:Staged;...
Why not run search/replace on the result?

what's the meaning of "type tags" in nodejs

assert.deepStrictEqual(actual, expected[, message]) in nodejs's docs:
Type tags of objects should be the same.
what's the meaning of "type tags"
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);
// Different type tags:
assert.deepStrictEqual(date, fakeDate);
typeof date and typeof fakeDate ,The results are all object, but different type tags
Type tags in Javascript, are referred to the word returned by typeof
For example for primitive values:
typeof({}) // returns 'object', this is the type tag
For non-primitive:
Object.getPrototypeOf(new Date) // returns 'Date {}' this is the type tag
If typeof is used with Date it will returns object which is right, because that would be the type tag for the primitive value, this is why using Object.getPrototypeOf is more accurate.
In the firsts JS implementations, the type tag were stored the first 1–3 bits and the the remaining 29–31, contained the actual data.
What the NodeJS docs says, it's that the result of Object.getPrototypeOf function when comparing two objects has to be the same to be considered as equal.
This is an old question that has been already answered, but I thought I might add that, although:
In the first implementation of JavaScript, JavaScript values were
represented as a type tag and a value. The type tag for objects was 0.
null was represented as the NULL pointer (0x00 in most platforms).
Consequently, null had 0 as type tag, hence the typeof return value
"object".
Type tags can also refer to an object's toStringTag.
The Symbol.toStringTag well-known symbol is a string valued property
that is used in the creation of the default string description of an
object. It is accessed internally by the Object.prototype.toString()
method.
The value associated to the well-know Symbol.toStringTag is used as the default string description of an object. Since every built-in object has a toStringTag value (except for null prototypes), it can be used to detect an object's class.
There's a package called typetags that has more information about it: typetags.org

WPFExtendedToolkit PropertyGrid Standard Values

I'm trying to display XmlElement's attributes in Xceed PropertyGrid. For that purpose I defined custom wrapper class. It wraps XmlElement, iterates over XmlAttributes and creates custom PropertyDescriptor for each XmlAttribute. All "virtual" properties' type is String. All works fine.
Now I want to have drop-down list of possible attribute values for every attribute that has restricted set of values. In Xceed's PropertyGrid, there is ItemsSourceAttribute for that. But it has to be applied as follows:
ItemsSourceAttribute(typeof(MyCustomItemsSource))
And here is the problem - I can not provide proper argument for MyCustomItemsSource constructor. What can I do about this?
It seems that there is another possibility - to define a TypeConverter, override GetStandardValues, and supply this converter to "virtual" property. But PropertyGrid just ignores this attribute.
How this simple task can be done with Xceed PropertyGrid?
Solved. I implemented custom editor
public class AttributeValuesEditor: Xceed.Wpf.Toolkit.PropertyGrid.Editors.ComboBoxEditor
{
protected override IEnumerable CreateItemsSource(PropertyItem propertyItem)
{
var property = propertyItem.PropertyDescriptor as XmlAttributePropertyDescriptor;
Debug.Assert(property!=null);
return property.GetCompletionValues();
}
}
Here, the context is passed into method in the form of PropertyItem. Now it is possible to differentiate between different attributes and return appropriate items.

Is this a bug in primefaces autocomplete?

I'm trying to put an autocomplete that fetches suggestions as a list of Entry<String, Integer>
<p:autoComplete completeMethod="#{suggester.suggestTopics}"
var="x1" itemLabel="#{x1.key}" itemValue="#{x1.value.toString()}"
value="#{topicController.selected}" />
Manged bean code is as follows:
private int selected;
public int getSelected() {
return selected;
}
public void setSelected(int selected) {
this.selected= selected;
}
But this fails saying the Integer class doesn't have method/property named key. If I remove the value attribute from autocomplete then it starts working properly. But when I put value attribute it starts expecting that the object inside var should be of the same type as that inside value attribute. I believe/expect it should be that the object inside itemValue should be of the same type as that inside value attribute.
I want to use POJOs for suggestions but pass just the entity Id to the value
Using :
Primefaces 3.1
JSF 2.1.6
I believe/expect it should be that the object inside itemValue should
be of the same type as that inside value attribute.
Yes this makes sense, and it is the same in the primefaces showcase:
<p:autoComplete value="#{autoCompleteBean.selectedPlayer1}"
id="basicPojo"
completeMethod="#{autoCompleteBean.completePlayer}"
var="p" itemLabel="#{p.name}" itemValue="#{p}"
converter="player" forceSelection="true"/>
As you see is var="p" and itemValue="#{p} where p is an instance of Player. And selectedPlayer1 is also an instance of Player.
I don't know if it works with a Map since the Primefaces example is called "Pojo support" and the suggestions should be a List of elements of the same type as in the value attribute.
I think you want to use the Simple auto complete , but instead you looked at the wrong example on the showcase of the Pojo Support
x1 refers to the int selected - while it expect to be referred to a POJO (with key and value properties.) , that's why you get the message
Integer class doesn't have method/property named key
Or simple use the Simple auto complete
As commented to Matt you dont need to rebuild Player(Pojo) from Db. You can set simply id property of Player(Pojo) and in action method may be utilize this id to fetch it from DB.
In your case in convertor you might do
Entry<String, Integer> e = new Entry<String, Integer>();
e.setId(value) // where value is passed in to convertor in method getAsObject.....
This value will be set to private Entry<String, Integer> selected
I have used Pojo autocomplete but not tried with generic classes.
Hope this helps.
I know the question is outdated but I've had the same problem.
The point is that you have to assign var to p (var="p"). I think it's terribly unobvious (documentation doesnot mention it has to be that way) 'cause I thought I can assign any var name I want.

"ValueExpression Map" of a JSF component

I'm storing value expressions in a JSF component with the f:attribute tag, e.g.:
<h:inputText ...>
<f:attribute name="myId1" value="#{bean.prop1}" />
<f:attribute name="myId2" value="#{bean.prop2}" />
<f:attribute name="myId3" value="#{bean.prop3}" />
</h:inputText>
Is there a way to access all of those value expressions programmatically? (without knowlegde of the names myId1, myId2,...)
Section 9.4.2 of the JSF 2.1 specification says that those values are stored "in the component’s ValueExpression Map".
That's the only occurrence of the term "ValueExpression Map" in the complete spec.
How do I access that map?
In the UIcomponent's Method getValueExpression() of the Jboss/Mojarra implementation the map
getStateHelper().get(UIComponentBase.PropertyKeys.bindings)
is used to obtain a single value expression.
I guess that map is a super set of the "ValueExpression Map"?
Can I be sure that all implementations and all inherited (standard) components use that map to store ValueExpressions?
Thanks.
In theory you should be able to see them all by UIComponent#getAttributes():
Map<String, Object> attributes = component.getAttributes();
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
System.out.printf("name=%s, value=%s%n", entry.getKey(), entry.getValue());
}
However, that doesn't work the way as you'd expect. It only returns static attributes. This does not seem to ever going to be fixed/implemented. See also JSF issue 636. I'd suggest to stick to attribtues with predefinied prefix and an incremental numerical suffix, like as you've presented in your example. That's also what I've always used to pass additional information from the component on to custom validators and converters. You can just collect them as follows:
Map<String, Object> attributes = component.getAttributes();
List<Object> values = new ArrayList<Object>();
for (int i = 1; i < Integer.MAX_VALUE; i++) {
Object value = attributes.get("myId" + i);
if (value == null) break;
values.add(value);
}
System.out.println(values);
An alternative to the answer given by BalusC might be to use nested facets or UIParameter components. Facets can be retrieved as a map using getFacets but you probably need to put an additional UIOutput inside each facet to access its value expression.
Nested UIParameters can be accessed by iterating over the components children and checking for instanceof UIParameter. UIParameters have name and value attributes and so could be easily converted to a map.
I have used parameters in a custom component, but I'm not sure how a standard UIInput like in your example reacts to these.
BalusC is right. UIComponent#getAttributes().get(name) gets values from both places - at first from attributes map and then if not found from "value expression map". To put some value you have to call UIComponent#setValueExpression(name, ValueExpression). If value is literal, it gets stored into the attribute map, otherwise into the "value expression map". Everything is ok then.

Resources