I have the following bean:
public class ContractBean {
private List<String> listNd;
private String nd;
public List<String> getListNd() {
return listNd;
}
public void setListNd(final List<String> listNd) {
this.listNd = listNd;
}
public String getNd() {
return nd;
}
public void setNd(final String nd) {
this.nd= nd;
}
}
I use apache Betwixt to output XML from my bean.
final BeanWriter beanWriter = new BeanWriter(outputWriter);
beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
beanWriter.getBindingConfiguration().setMapIDs(false);
beanWriter.enablePrettyPrint();
beanWriter.setWriteEmptyElements(false);
beanWriter.getBindingConfiguration().setObjectStringConverter(new CustomObjectStringConverter());
beanWriter.write(obj);
The listND attribute of my bean is null, but i still get:
<contract>
<listNd/>
<nd>22222</nd>
</contract>
How can I remove empty lists from the output XML ?
Related
Error converting entity with source attribute name content in source fiels with camel case part
Example: in source model i heve a String field edgeId, and in target model i heve a field Long id, the match is true. This generate a exception, java.lang.NumberFormatException, how to ignore this match.
This is occurre with another attribute names
package br.com.combinado;
import org.modelmapper.ModelMapper;
public class TestModelMapper {
public static void main(String[] args) {
Target target = new Target();
target.setTesteBatataFrita("batataFrinta");
ModelMapper mapper = new ModelMapper();
Source source = mapper.map(target, Source.class);
System.out.println(source);
}
private static class Source {
private Long frita;
public Long getFrita() {
return frita;
}
public void setFrita(Long frita) {
this.frita = frita;
}
}
private static class Target {
private String testeBatataFrita;
public String getTesteBatataFrita() {
return testeBatataFrita;
}
public void setTesteBatataFrita(String testeBatataFrita) {
this.testeBatataFrita = testeBatataFrita;
}
}
}
I solved by adding a add a SourceNameTokenizer
mapper.getConfiguration().setSourceNameTokenizer(new NameTokenizer() {
public String[] tokenize(String name, NameableType nameableType) {
return new String[] { name };
}
});
Or
#Bean
public ModelMapper modelMapper() {
final ModelMapper mapper = new ModelMapper();
mapper.getConfiguration().setDestinationNameTokenizer((name, nameableType) -> new String[] { name });
mapper.getConfiguration().setSourceNameTokenizer((name, nameableType) -> new String[] { name });
return mapper;
}
Old question but in latest versions I found a way to solve it with
mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
To the best of my understanding, Jackson will
serialize a public instance variable to the variable name
public List<String> myStrings = new ArrayList<>();
serializes to
{ 'myStrings' : [ ... ] }
serialize a private instance variable to the variable name if it has a public getter named getVariable():
private List<String> myStrings = new ArrayList<>();
public List<String> getMyStrings() { return myStrings; }
serializes similar to
{ 'myStrings' : [ ... ] }
However, what I am trying to achieve is to serialize it to a String (instead of array of Strings) based on another method, but keep the JSON key (based on #JsonInclude(JsonInclude.Include.NON_NULL) suppressing the original accessor in some cases
#JsonInclude(JsonInclude.Include.NON_NULL)
private boolean firstStringOnly = true;
private List<String> myStrings = new ArrayList<>();
public List<String> getMyStrings() { return firstStringOnly ? null: myStrings; }
public String getFirstString() { return firstStringOnly ? myStrings.get(0) : null; }
Desired JSON serialization:
For firstStringOnly==true: { 'myStrings' : 'first_String' } (using getFirstString())
For firstStringOnly==false: { 'myStrings' : [ ... ] } (using getMyStrings())
Is this possible to do? I'm specifically looking to avoid using custom serializers, and do this via annotations only.
You can assume a reasonably recent version of Jackson and Java 8.
Just to re-iterate, the question constraints are:
* NO custom serializer
* Both use cases produce the same JSON key
You can generalize getMyStrings() method and make it return Object. And inside check the flag and return first value or all values. Here is my sample
public class tst {
private static class YourObject {
private boolean firstStringOnly;
private List<String> myStrings = new ArrayList<>();
public YourObject(boolean firstStringOnly) {
this.firstStringOnly = firstStringOnly;
this.myStrings.add("str1");
this.myStrings.add("str2");
}
public Object getMyStrings(){
return firstStringOnly ? myStrings.get(0) : myStrings;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new YourObject(true)));
System.out.println(mapper.writeValueAsString(new YourObject(false)));
}
}
The output is
{"myStrings":"str1"}
{"myStrings":["str1","str2"]}
EDIT: Sorry, i have misread your initial question. I assume you want to keep both of the typed getters. Would this work for you?
public class TestClass {
private boolean firstStringOnly = true;
private List<String> myStrings = new ArrayList<>();
#JsonIgnore
public boolean isFirstStringOnly() {
return firstStringOnly;
}
public void setFirstStringOnly(boolean firstStringOnly) {
this.firstStringOnly = firstStringOnly;
}
#JsonIgnore
public List<String> getMyStrings() {
return firstStringOnly ? null : myStrings;
}
#JsonIgnore
public String getFirstString() { return firstStringOnly ? myStrings.get(0) : null; }
#JsonProperty("myStrings")
public Object getMyStringsForSerialization() {
return firstStringOnly ? getFirstString() : getMyStrings();
}
public void setMyStrings(List<String> myStrings) {
this.myStrings = myStrings;
}
Currently I have form like below:
public class Form {
private String listOfItems;
public String getListOfItems() {
return listOfItems;
}
public void setListOfItems(String listOfItems) {
this.listOfItems= listOfItems;
}
}
For instanse listOfItems equals to the following string "1,2,3".
The goal is to serialize this form to following format:
{
"listOfItems": [1, 2, 3]
}
It would be good to know how to correctly do such thing? As I know it is possible to create some custom serializer then mark appropriate getter method with it, like this #JsonSerialize(using = SomeCustomSerializer).
But not sure whether it is correct approach, probably any default implementations already exist.
If you can edit your Form class:
public class Form {
private String listOfItems;
public String getListOfItems() {
return listOfItems;
}
public void setListOfItems(String listOfItems) {
this.listOfItems = listOfItems;
}
#JsonProperty("listOfItems")
public List<Integer> getArrayListOfItems() {
if (listOfItems != null) {
List<Integer> items = new ArrayList();
for (String s : listOfItems.split(",")) {
items.add(Integer.parseInt(s)); // May throw NumberFormatException
}
return items;
}
return null;
}
}
By default Jackson looks for getters for serializing. You can override this by using #JsonProperty annotation.
ObjectMapper mapper = new ObjectMapper();
Form form = new Form();
form.setListOfItems("1,2,3");
System.out.print(mapper.writeValueAsString(form));
Outputs:
{"listOfItems":[1,2,3]}
<PlayListSettings>
<PlayList>
<id>PlayList1</Name>
<File class="string">/mnt/sdcard/Video1</File>
</PlayList>
</PlayListSettings>
This is my Serialized xml,where File is an arrayList of strings. I could remove the class="string" using xstream.aliasSystemAttribute(null, "class");
and the output is
<PlayListSettings>
<PlayList>
<id>PlayList1</Name>
<File>/mnt/sdcard/Video1</File>
</PlayList>
</PlayListSettings>
How do i deserialize using XStream?
You can use the #XStreamImplicit annotation for it. Here is a fully working example:
#XStreamAlias("PlayList")
public final class PlayList {
#XStreamImplicit(itemFieldName = "File")
private final List<String> files = new ArrayList<>();
public void addFile(final String file) {
checkFile(file);
files.add(file);
}
public void removeFile(final String file) {
checkFile(file);
files.remove(file);
}
public List<String> getFiles() {
return Collections.unmodifiableList(files);
}
private void checkFile(final String file) {
if (file == null) {
throw new NullPointerException();
} else if (file.isEmpty()) {
throw new IllegalArgumentException("is empty");
}
}
public static void main(String[] args) {
final PlayList playList = new PlayList();
playList.addFile("Foo");
playList.addFile("Bar");
// Serialize
final XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
final String xml = xstream.toXML(playList);
System.out.println(xml);
// Deserialize
final PlayList playList2 = (PlayList) xstream.fromXML(xml);
for (final String file : playList.getFiles()) {
System.out.println(file);
}
}
}
The output looks like:
<PlayList>
<File>Foo</File>
<File>Bar</File>
</PlayList>
I need to format the output (xml) of a restful service using Jersey according to following scenario
I have a class with key value pair as follows.
#XmlRootElement(name="columnValues")
public class KeyValueDTO {
private String key;
private String val;
#XmlElement(name="column")
public String getKey() {
return key;
}
#XmlElement(name="value")
public String getVal() {
return val;
}
}
Suppose I have list like this which is returned by rest service:
List<KeyValueDTO> mylist = new ArrayList<KeyValueDTO>();
KeyValueDTO dto1 = new KeyValueDTO();
dto1.key = "Name";
dto1.val = "alex";
KeyValueDTO dto2 = new KeyValueDTO();
dto2.key = "Age";
dto2.val = 23
mylist.add(dto1);
mylist.add(dt02);
And I want to generate the output as follow
<Name>alex</Name>
<Age>20</Age>
But currently it is giving following output
<column>Name</column>
<value>alex</column>
<column>Age</column>
<value>20</column>
Can anyone let me know how to achieve this?
You could try using an XmlAdapter:
public class KeyValueAdapter extends XmlAdapter<String, List<KeyValueDTO>> {
#Override
public List<KeyValueDTO> unmarshal(String v) throws Exception {
// Needs implementation
return null;
}
#Override
public String marshal(List<KeyValueDTO> vs) throws Exception {
StringBuffer buffer = new StringBuffer();
for (KeyValueDTO v: vs) {
buffer.append(String.format("<%s>%s</%1$s>", v.key, v.val));
}
return buffer.toString();
}
}
And then add that adapter to your bean:
#XmlRootElement
public static class Wrapper {
#XmlJavaTypeAdapter(KeyValueAdapter.class)
List<KeyValueDTO> dtos;
}