Simple Framework XML remove empty attribute - java

Simple question! I have such a class, and if the attribute is empty (or just null) then this attribute should not appear at all in the generated XML file
XML File: (note empty string in attribute abc, i don't want something like that!)
<root abc="">
<example>somethin</example>
</root>
Java Class
#Root
public class Data {
#Element(name="example">
private String value;
#Attribute(name="abc", required=false)
private String s;
public String getString() {
return s;
}
I tried with a #Convert but it works only with #Element... Is there any way to remove the attribute in the xml file when it is empty?

Use a custom XMLAdapter as such:
public class ExampleAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String exampleString) throws Exception {
return exampleString;
}
#Override
public String unmarshal(String exampleString) throws Exception {
if (exampleString.isEmpty()) {
return null;
}
return exampleString;
}}
And then just associate your property with it:
#XmlAttribute
#XmlJavaTypeAdapter(ExampleAdapter.class)
public void setExample(String example) {
this.example = example;
}

Related

Jackson: How to edit existing property to the JSON without modifying the POJO?

I need to edit the name of "existing field" in POJO instead of adding "extra_field". Is it possible with the approach referenced link below?
Please note I do not want to use #JsonProperty annotation.
Requirement is, I have a POJO and want to use different field name every time without change in POJO. For example I have a field c_id in POJO and some times it need to write as cust_id and another time it would be my_id.
Also note I cannot change implementation of POJO as it is already used in several modules and have generic implementation.
POJO Example:
class MyPojo {
String id;
// getter and setters
}
Expected output can be the following: (name of field can be changed)
{"cust_id": "123"}
{"my_id": "123"}
Mixins
The easiest way to modify the output of Jackson without adding annotations to the original POJO is using mixins.
Just define a mixin-class with the necessary annotations and indicate to Jackson that you want to use the mixin when serializing the original object.
private static class MyPojoMixin {
#JsonProperty("cust_id")
private String id;
}
public String serializeWithMixin(MyPojo p) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(MyPojo.class, MyPojoMixin.class);
return mapper.writeValueAsString(p);
}
Custom property naming strategy
If you need to programmatically change the field-name, you might not be able to use the mixin solution. You could then use a custom PropertyNamingStrategy:
public class IdRenamingStrategy extends PropertyNamingStrategy {
private final PropertyNamingStrategy inner;
private final String newIdPropertyName;
public IdRenamingStrategy(String newIdPropertyName) {
this(PropertyNamingStrategy.LOWER_CAMEL_CASE, newIdPropertyName);
}
public IdRenamingStrategy(PropertyNamingStrategy inner, String newIdPropertyName) {
this.inner = inner;
this.newIdPropertyName = newIdPropertyName;
}
private String translate(String propertyName) {
if ("id".equals(propertyName)) {
return newIdPropertyName;
} else {
return propertyName;
}
}
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return inner.nameForField(config, field, translate(defaultName));
}
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return inner.nameForGetterMethod(config, method, translate(defaultName));
}
#Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return inner.nameForSetterMethod(config, method, translate(defaultName));
}
#Override
public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) {
return inner.nameForConstructorParameter(config, ctorParam, translate(defaultName));
}
}
This can be used like this:
public String serializeWithPropertyNamingStrategy(MyPojo p) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new IdRenamingStrategy("cust_id"));
return mapper.writeValueAsString(p));
}

Remove properties from JSON in some cases

I have a class like this:
public class SampleDto {
private String normalProperty1;
private String normalProperty2;
private String normalProperty3;
private String sensitiveProperty1;
private String sensitiveProperty2;
public String getNormalProperty1() {
return normalProperty1;
}
public void setNormalProperty1(String normalProperty1) {
this.normalProperty1 = normalProperty1;
}
public String getNormalProperty2() {
return normalProperty2;
}
public void setNormalProperty2(String normalProperty2) {
this.normalProperty2 = normalProperty2;
}
public String getNormalProperty3() {
return normalProperty3;
}
public void setNormalProperty3(String normalProperty3) {
this.normalProperty3 = normalProperty3;
}
public String getSensitiveProperty1() {
return sensitiveProperty1;
}
public void setSensitiveProperty1(String sensitiveProperty1) {
this.sensitiveProperty1 = sensitiveProperty1;
}
public String getSensitiveProperty2() {
return sensitiveProperty2;
}
public void setSensitiveProperty2(String sensitiveProperty2) {
this.sensitiveProperty2 = sensitiveProperty2;
}
}
There are parts in the application where i need to serialize it as it is because the object is in a secure environment.
But i need to store the json in a db and store it without the sensitiveProperties, I can't just ignore the properties because they are needed in the other processes.
I was thinking to use Jackson views to solve the problem but i don't know if there is something special in Jackson where I can say, every json object that has the property "sensitiveProperty1" set it to null.
I'm using Java and Jackson
I think that this site covers what you're looking for pretty well.
Essentially what you'll want to do is to add #JsonIgnoreProperties(value = { "intValue" }) at the class level or #JsonIgnore at the field level and then Jackson should take care of the rest for you.
In your case that would look something like:
public class SampleDto {
#JsonIgnore
private String normalProperty1;
private String normalProperty2;
...

Using getter methods for generated values. Good or bad? [duplicate]

I'm using some functionality in Java that I don't really understand so I want to read up on it so that I can use it more effectively. The problem is that I don't know what it is called so it makes it difficult to get more information on it:
I have a class Foo defined like this:
private String _name;
private Bar _bar;
//getters and setters
And Bar:
private String _code;
//getters and setters
public String get_isCodeSmith()
{
boolean rVal = _code.toLowerCase().contains("smith");
return rVal;
}
Somehow, in my JSP pages (when I have a Session variable called Foo) I am able to write logic tags like this:
<logic:equal name="Foo" property="_bar._isCodeSmith" value="true">
And even though there is no attribute _isCodeSmith in my class Bar, it runs the get_isCodeSmith() method automatically.
What is this called and where can I find out more?
This is the Javabeans mechanism. Properties are identified not by fields, but by getter (accessor) and / or setter (mutator) methods.
For more technical info, read the JavaBeans spec
Or have a look at this simple test class:
public class TestBean {
private String complete;
public String getComplete() { return complete; }
public void setComplete(final String complete) { this.complete = complete; }
private String getterOnly;
public String getGetterOnly() { return getterOnly; }
private String setterOnly;
public void setSetterOnly(final String setterOnly) { this.setterOnly = setterOnly; }
public String getNoBackingField() { return ""; }
}
and the simple JavaBeans analysis:
public class Test {
public static void analyzeBeanProperties(final Class<?> clazz) throws Exception {
for (final PropertyDescriptor propertyDescriptor
: Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors()) {
System.out.println("Property name: " + propertyDescriptor.getName());
System.out.println("Getter method: " + propertyDescriptor.getReadMethod());
System.out.println("Setter method: " + propertyDescriptor.getWriteMethod());
System.out.println();
}
}
public static void main(final String[] args) throws Exception {
analyzeBeanProperties(TestBean.class);
}
}
Output:
Property name: complete
Getter method: public java.lang.String test.bean.TestBean.getComplete()
Setter method: public void test.bean.TestBean.setComplete(java.lang.String)
Property name: getterOnly
Getter method: public java.lang.String test.bean.TestBean.getGetterOnly()
Setter method: null
Property name: noBackingField
Getter method: public java.lang.String test.bean.TestBean.getNoBackingField()
Setter method: null
Property name: setterOnly
Getter method: null
Setter method: public void test.bean.TestBean.setSetterOnly(java.lang.String)
<logic:equal name="Foo" property="a.b.c" value="true">
means Foo.getA().getB().getC()
Doesn't matter if fields exist. Only getters are mandatory.

How to iterate with the S tag a collection of Object

I have a collection of objects in a Struts2 action:
public class TakeClassification implements Action{
List<Classificazione> classificazioni;
#Autowired
private Servizi servizi;
public List<Classificazione> getClassificazioni() {
return classificazioni;
}
public void setClassificazioni(List<Classificazione> classificazioni) {
this.classificazioni = classificazioni;
}
public String execute() throws Exception {
classificazioni = servizi.getClassificazione();
return SUCCESS;
}
public void setServizi(Servizi servizi) {
this.servizi = servizi;
}
}
I want to iterate the elements of classificazioni in jsp with the s tag "iterator".
To specify I want to fill the items of a combobox with the expression classificazioni.nome that returns a String.
In struts tag you can use <s:combobox>.
See: http://www.mkyong.com/struts2/struts-2-scombobox-combo-box-example/
It is the parameter list

Polymorphism in XStream serialization and deserialization

I have these classes:
#XStreamAlias("person")
public class PersonConfig {
private AnimalConfig animalConfig;
}
public interface AnimalConfig {}
#XStreamAlias("dog");
public class DogConfig extend AnimalConfig {}
#XStreamAlias("cat");
public class CatConfig extend AnimalConfig {}
And I would like to be able to deserialize this xml with the classes above:
<person>
<dog/>
<person>
As well as deserialize this xml too, with the same classes:
<person>
<cat/>
<person>
So that in both cases, the PersonConfig's field animalConfig is filled. In the first XML with a DogConfig instance and in the second XML with a CatConfig instance.
Is this possible by adding some annotation to make this work?
It seems XStream does not allow you to do it easily.
Your question is similar to this one, asking for managing something like a xsd:choice with XStream.
If you don't necessarily need to use XStream, JAXB will allow you to do it easily :
#XmlRootElement(name="person")
public class PersonConfig {
private AnimalConfig animalConfig;
#XmlElementRefs({
#XmlElementRef(name="cat", type=CatConfig.class),
#XmlElementRef(name="dog", type=DogConfig.class)
})
public AnimalConfig getAnimalConfig() {
return animalConfig;
}
public void setAnimalConfig(AnimalConfig animalConfig) {
this.animalConfig = animalConfig;
}
}
After some researches, listing all available classes for your property can be avoided if you choose to use the XmlAdapter.
In Blaise Doughan link, the example uses an abstract class, not an interface.
Edit :
As Blaise Doughan said in its comment, #XmlElementRef is better suited for this purpose. Code has been updated accordingly.
You can write a converter.
public class CustomConverter implements Converter {
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
// TODO: Get annotation value from object 'source' with name of tag via Reflection.
// Or add a method to the AnimalConfig interface giving you tag name to put to serialization output.
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
// TODO: use reflection to create animal object based on what you xml tag you have at hahd.
return context.convertAnother(context.currentObject(), SomeAnimalClazz.class);
}
public boolean canConvert(Class type) {
return type.equals(AnimalConfig.class);
}
}
There's a disadvantage: polymorphism will require you to use Java Reflection API and performance degradation.
This is quite easy. You just have to do it right and not like my previous speakers. When you process the annotations, XStream can assign those classes.
#XStreamAlias("person")
public class PersonConfig {
private AnimalConfig animalConfig;
public String toXml() {
XStream xstream = new XStream();
xstream.processAnnotations(DogConfig.class);
xstream.processAnnotations(CatConfig.class);
return xstream.toXML(this);
}
}
public interface AnimalConfig {}
#XStreamAlias("dog");
public class DogConfig implements AnimalConfig {}
#XStreamAlias("cat");
public class CatConfig implements AnimalConfig {}
It works out of the box, with out any annotations...
private static interface Test {
String getName();
Params getParams();
}
private static interface Params {
}
private static class OneParams implements Params {
private String oneValue;
public String getOneValue() {
return oneValue;
}
public void setOneValue(String oneValue) {
this.oneValue = oneValue;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("OneParams [oneValue=");
builder.append(oneValue);
builder.append("]");
return builder.toString();
}
}
private static class TwoParams implements Params {
private String twoValue;
public String getTwoValue() {
return twoValue;
}
public void setTwoValue(String twoValue) {
this.twoValue = twoValue;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("TwoParams [twoValue=");
builder.append(twoValue);
builder.append("]");
return builder.toString();
}
}
private static class OneTest implements Test {
private String name;
private Params params;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public Params getParams() {
return params;
}
public void setParams(Params params) {
this.params = params;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("OneTest [name=");
builder.append(name);
builder.append(", params=");
builder.append(params);
builder.append("]");
return builder.toString();
}
}
---- now deserialize like this...
System.out
.println(ser
.deserialize("<XStreamTest_-OneTest><name>OneTest</name><params class=\"XStreamTest$OneParams\"><oneValue>1</oneValue></params></XStreamTest_-OneTest>"));
System.out
.println(ser
.deserialize("<XStreamTest_-OneTest><name>TwoTest</name><params class=\"XStreamTest$TwoParams\"><twoValue>2</twoValue></params></XStreamTest_-OneTest>"));

Categories