I have an application that uses XStream to serialize and deserialize classes to XML. It works great. I got a question whether static inner classes are serializable. Per the XStream's FAQs, it can. However, a Test class that has a nested static class doesn't seem like serializing the data.
public static class TestInner
{
public static String param1;
public static String param2;
public static String getParam1()
{
return param1;
}
public static void setParam1(final String param1)
{
TestInner.param1 = param1;
}
public static String getParam2()
{
return param2;
}
public static void setParam2(final String param2)
{
TestInner.param2 = param2;
}
}
final XStream xstream = new XStream();
final TestInner inner = new Test.TestInner();
inner.setParam1("valueparam1");
inner.setParam2("valueparam2");
logger.info("{}", xstream.toXML(inner));
Yields,
<test.Test_-TestInner/>
Is this a known behavior or limitation of XStream?
Tested using the Xstream tutorial (which is fairly the same as the code you gave) and is working [the difference between your code and mine is my variables are not static] and I think that is the reason. Used the following dependency as well
package com.stackoverflow;
public class TestRunnerOuter {
public static class TestRunner{
private String name;
public TestRunner() {}
public TestRunner(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
and then ->
XStream xstream = new XStream();
TestRunner inner = new TestRunnerOuter.TestRunner();
inner.setName("Test");
System.out.println(xstream.toXML(inner));
dependency->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.11.1</version>
</dependency>
output ->
<com.stackoverflow.TestRunnerOuter_-TestRunner>
<name>Test</name>
</com.stackoverflow.TestRunnerOuter_-TestRunner>
Related
Good day everyone,
Im struggling with serializing object with nested object having custom name with # JsonProperty.
So, here it is:
public class Wrapper {
public final Payload payload;
public Wrapper(String name){
this.payload = new Payload(name);
}
public static final class Payload{
#JsonProperty("customName")
public final String name;
#JsonCreator
public Payload(#JsonProperty ("customName") String name){
this.name = name;
}
}
}
So, in every test I see non-custom name - "name". I added getter with #JsonProperty without any success.
My test class:
#JsonTest
public class SerializeWrapperTest {
#Test
void whenSerialiseThanCorrect() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Wrapper wrapper =
new Wrapper("name");
String json = objectMapper.writeValueAsString(wrapper);
Assertions.assertEquals("{"payload":{"customName":"name"}}",json);
}
}
Test results:
Expected :{"payload":{"customName":"name"}}
Actual :{"payload":{"name":"name"}}
org.opentest4j.AssertionFailedError.
Edited.
If I understood it correct , you need to have a custom property in json for the field , "name".
For that you need to do following -
public class Wrapper {
public final Payload payload;
public Wrapper(String name){
this.payload = new Payload(name);
}
public static final class Payload{
#JsonProperty("customName")
public final String name;
public Payload(String name){
this.name = name;
}
}
JUnit -
public class WrapperTest {
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void whenSerialiseThanCorrect() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Wrapper wrapper =
new Wrapper("Ajeet");
String json = objectMapper.writeValueAsString(wrapper);
System.out.println(json);
}
}
}
In my REST web service I need to accept JSON that can have two different structures.
Currently I have:
#Path("/")
public class MyAppResource {
...
#Context private HttpServletRequest request;
...
#POST
#Produces(MediaType.APPLICATION_JSON)
public MyResponseItem check(MyRequestItem body) {
...
}
}
where
public class MyRequestItem {
...
#JsonCreator
public MyRequestItem(#JsonProperty("data") ArrayList<TextItem> data) {
...
}
...
}
and
class TextItem {
...
#JsonCreator
public TextItem(#JsonProperty("count") int count,
#JsonProperty("text") String text) {
...
}
...
}
So it accepts JSON of the form {"data":[{"count":123,"text":"abc"},...]}.
In addition to the above format I need to accept this format: {"data":["abc",...]}. That is, I think I need to change TextItem so that it can either be a String or a class as above.
How to achieve this?
If you don't mind it to be the same class for both cases(TextItem), the easiest option for you is to add 1 more TextItem constructor with single string argument.
Here is demo:
public class Main {
public static String json1 = "{\"data\":[{\"count\":123,\"text\":\"abc\"}]}";
public static String json2 = "{\"data\":[\"abc\"]}";
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json1, MyRequestItem.class));
System.out.println(mapper.readValue(json2, MyRequestItem.class));
}
#Data // lombok.Data;
#ToString // lombok.ToString;
public static class MyRequestItem {
private List<TextItem> data;
#JsonCreator
public MyRequestItem(#JsonProperty("data") ArrayList<TextItem> data) {
this.data = data;
}
}
#Data
#ToString
public static class TextItem {
private int count;
private String text;
#JsonCreator
public TextItem(#JsonProperty("count") int count,
#JsonProperty("text") String text) {
this.count = count;
this.text = text;
}
// this is the only thing you need to add to make it work
public TextItem( String text) {
this.text = text;
}
}
}
Result:
MyRequestItem(data=[TextItem(count=123, text=abc)])
MyRequestItem(data=[TextItem(count=0, text=abc)])
I currently have my POJO class as such for deserializing a json source.
public class OpenBuilding extends Building {
#JsonProperty("BuildingPostCode")
#Override
public String getPostcode() {
return super.getPostcode();
}
}
Where the parent class is as such
public abstract class Buidling {
protected String postcode;
public String getPostcode() {
return this.postcode;
}
}
My issue is that the String postcode isn't getting mapped at all. It works when using the annotation on the field. However since it is an inherited field and I have other children of Building, which use different property names for the same data, I cannot have it implemented in that way.
For example:
public class DirectedBuilding extends Building {
#JsonProperty("Pseudo_PostCode")
#Override
public String getPostcode() {
return super.getPostcode();
}
}
Perhaps try defining a constructor with #JsonCreator.
class Parent {
private final String foo;
public Parent(final String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
}
class Child extends Parent {
#JsonCreator
public Child(#JsonProperty("foo") final String foo) {
super(foo);
}
#JsonProperty("foo")
public String getFoo() {
return super.getFoo();
}
}
public static void main(String[] args) throws Exception {
final ObjectMapper objectMapper = new ObjectMapper();
final Child toSerialize = new Child("fooValue");
// Serialize the object to JSON
final String json = objectMapper.writer()
.withDefaultPrettyPrinter()
.writeValueAsString(toSerialize);
// Prints { "foo" : "fooValue" }
System.out.println(json);
// Deserialize the JSON
final Child deserializedChild = objectMapper.readValue(json, Child.class);
// Prints fooValue
System.out.println(deserializedChild.getFoo());
}
I have a list of utilities that derive from:
abstract public class BaseUtil implements Callable{
public String name;
public StreamWrapper data;
public void setData(StreamWrapper stream){ this.data = stream; }
private static Class me = BaseUtil.class;
private static Method[] availableUtilities = me.getDeclaredMethods();
public static Method[] getUtilities(){ return availableUtilities; }
}
I want to, at each node, be able to assign a utility to it, something like:
Initialize(String utilName){
activeUtility = utilName;
gk = new GateKeeper(BaseUtil.getUtilities() <something>);
}
public class GateKeeper {
GateKeeper(BaseUtil util) {
this.util = util;
}
private BaseUtil util;
But I'm unsure on how to get the specific utility class from just the String passed in. An example utility is:
public class WordLengthUtil extends BaseUtil {
private String name = "WordLength";
public Integer call() {
System.out.println(this.data);
return Integer.valueOf(this.data.length());
}
}
You can use reflection:
String name = "WordLength";
String className = hashMap.get(name);
Callable plugin = (Callable) Class.forName(className).newInstance();
use HashMap to store binding between className and string identifier
I have a question concerning Json deserialization using Jackson.
I would like to deserialize a Json file using a class like this one:
(taken from http://wiki.fasterxml.com/JacksonInFiveMinutes)
public class User
{
public enum Gender { MALE, FEMALE };
public static class Name {
private String _first, _last;
public String getFirst() { return _first; }
public String getLast() { return _last; }
public void setFirst(String s) { _first = s; }
public void setLast(String s) { _last = s; }
}
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
A Json file can be deserialized using the so called "Full Data Binding" in this way:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
My problem is the usage of the inner class "Name". I would like to do the same thing without using inner classes. The "User" class would became like that:
import Name;
import Gender;
public class User
{
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
This means to find a way to specify to the mapper all the required classes in order to perform the deserialization.
Is this possible? I looked at the documentation but I cannot find any solution.
My need comes from the fact that I use the Javassist library to create such classes, and it does not support inner or anonymous classes.
Thank you in advance
There should be no difference between the static inner class Name, and the top-level class of the same name. The Jackson runtime should not be able to meaningfully distinguish between the two situations.
Have you tried moving the Name class out of User, changing it into a top-level class? It should still work as before.
edit: I just tried this, and it works fine when Name is a top-level class. The example had it as an inner class for the sake of brevity, I suspect.
mr. Skaffman's answer is right on. The only additional thing to mention is that unlike JAXB, Jackson does not generally require you to specify classes you operate on, except for the root class (and not always even that, if you use Polymorphic Handling).