Deserializing JSON flat object using immutable classes with Jackson - java

I'm quite new to the Jackson library (version 1.9). I'm using it only since a couple of weeks, and I find it very flexible and time-saving when it's about serializing and deserializing objects in Java.
I'm experiencing troubles, though, into deserializing "flat" JSONs to a class which is a composition of another, when both are meant to be immutable.
My situation is pretty much the following:
class Foo {
private final String var1;
Foo(String var1) {
this.var1 = var1;
}
// getters omitted
}
class A {
private final Foo foo;
private final String var2;
A(/* #JsonUnwrapped doesn't work here */ Foo foo, String var2) {
this.foo = foo;
this.var2 = var2;
}
#JsonUnwrapped
Foo getFoo() {
return foo;
}
String getVar2() {
return var2;
}
}
class B extends Foo {
private final String var2;
B(String var1, String var2) {
super(var1);
this.var2 = var2;
}
// getters omitted
}
And the JSON to deserialize is something like this:
{ "var1" : "some_value", "var2" : "some_other_value" }
The question is: is there an annotation-based way (so, without the need of using a custom deserializer) to tell Jackson to compose the given JSON to a 'A' instance?
I've tried using the #JsonUnwrapped attribute for the Foo argument in class 'A' constructor, but it's not supported in multi-argument constructor as it would need a JsonProperty to work (which doesn't make sense, because there is actually no single property for those items).
Serialization, instead, works perfectly using this pattern.
It would also work with a non-immutable class by using separate setters, but I'd like to know if there's a way to do the same by only using the constructors (or a builder, which would make sense as in reality the fields are much more than the one in the example).
The very same method obviously works with class 'B' which inherits from 'Foo'.
Thanks in advance.

Note that Jackson's deserialization processing doesn't necessarily respect the immutability of final fields. So, a simple approach would be to just provide no-argument (private) constructors for Jackson to use.
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
// {"var1":"some_value", "var2":"some_other_value"}
String jsonInput = "{\"var1\":\"some_value\", \"var2\":\"some_other_value\"}";
ObjectMapper mapper = new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
A a = new A(new Foo("some_value"), "some_other_value");
System.out.println(mapper.writeValueAsString(a));
// output: {"var1":"some_value","var2":"some_other_value"}
A aCopy = mapper.readValue(jsonInput, A.class);
System.out.println(mapper.writeValueAsString(aCopy));
// output: {"var1":"some_value","var2":"some_other_value"}
}
}
class Foo
{
private final String var1;
Foo(String var1) {this.var1 = var1;}
private Foo() {this.var1 = null;}
}
class A
{
#JsonUnwrapped
private final Foo foo;
private final String var2;
A(Foo foo, String var2)
{
this.foo = foo;
this.var2 = var2;
}
private A()
{
this.foo = null;
this.var2 = null;
}
}
If you really don't want to provide such (extra) constructors, then it would be nice if a similar solution could be devised using #JsonCreator, but I wasn't able to get such a thing to work. So, I recommend logging an enhancement request at https://github.com/FasterXML/jackson-core/issues, maybe to better support annotating a #JsonCreator argument with both #JsonUnwrapped and #JsonProperty.

Unfortunately there are certain combinations of features that may not be possible to implement properly; and this may be one of those (I am not 100% sure: feel free to file a Bug/RFE for Jackson github issues or Jira). This is because the way #JsonUnwrapped and #JsonCreator both require potential reordering of data; and also because the order of creating actual instance complicates things.
So while conceptually this should be possible, there may be implementation difficulties.
As to Jackson 2.0: I would definitely try it over 1.9 because some parts of #JsonUnwrapped handling have been improved; and any fixes/improvements will be added there. 1.9 branch will get bugfixes backported wherever possible, but no new features will be added.

Related

Java to JSON: Specify which fields get excluded for each conversion

As mentioned here, I know that I can convert Java objects to JSON (with Jackson)
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(objectToBeConverted);
I know that I can exclude fields from being included in the JSON string using the #JsonIgnore annotation, but what if I want to convert the same class to JSON multiple times, but each time choosing different fields to ignore?
For example, if I have a class
class Foo {
int a;
int b;
...
}
can I do something like
Foo foo = new Foo();
String json1 = ow.writeValueAsString(foo).excludeField('b');
String json2 = ow.writeValueAsString(foo).excludeField('a');
so that the resulting strings look like
// json1
{
a: 1234
}
// json2
{
b: 5678
}
If Jackson can't do it, maybe Gson can? Or another library?
You can try using different mix-in interfaces. I found two ways to do this.
Use methods for reading properties. You can then create a mix-in class that only defines the properties to exclude:
public interface ExludeA {
#JsonIgnore
int getA();
}
Use #JsonIncludeProperties to not tell which properties to exclude, but which properties to include:
#JsonIncludeProperties({ "b", "c" })
public interface ExludeA {
}
In both cases, add that mix-in to the object mapper:
objectMapper.addMixIn(Foo.class, ExcludeA.class);
There is one very, very important thing though - you must use a new ObjectMapper for each mix-in. If you use an ObjectMapper instance to serialize a Foo instance without mix-ins, then adding the mix-in won't help. That's probably because ObjectMapper instances cache some stuff.
Here is a simple approach if you could box up all primitive type in Foo.
For example: int -> Integer, boolean -> Boolean
#JsonInclude(Include.NON_NULL)
class Foo {
Integer a;
Integer b;
...
}
Then, just make a copy of Foo and set the property which you want to ignore to null.
Foo foo = new Foo();
foo.setA(1234);
foo.setB(5678);
Foo foo1 = objectMapper.readValue(objectMapper.writeValueAsString(foo), Foo.class); // make a copy of Foo
foo1.setB(null); // force to ignore B
String json1 = ow.writeValueAsString(foo1); // it will be {a:1234}
There is multiple solution based on your need:
First:
You can just define two different DTO for your purpose and every time you need to each one just use it.
Second:
You can use #JsonInclude(JsonInclude.Include.NON_NULL) annotation for the properties:
class Foo {
#JsonInclude(JsonInclude.Include.NON_NULL)
int a;
#JsonInclude(JsonInclude.Include.NON_NULL)
int b;
}
P.S: You can use this annotation on class level as:
#JsonInclude(JsonInclude.Include.NON_NULL)
class Foo {
int a;
int b;
}
Third:
Use can define a filter to ignore properties based on different conditions.
Define a simple class for your filter:
public class YourConditionalFilter {
#Override
public boolean equals(int a) {
return a == 1234;
}
}
And then add this filter as annotation on top of the property:
#JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = YourConditionalFilter.class)
int a;

Deserialize String as List of Strings

I have a POJO that contains the following attributes
public class Example {
#JsonProperty("inputFoo")
private String foo
#JsonProperty("inputBar")
private String bar
#JsonProperty("inputBaz")
#JsonDeserialize(using = MyDeserializer.class)
private Set<String> baz
}
The JSON that I am working with to represent this data currently represents the baz attribute as a single string:
{"inputFoo":"a", "inputBar":"b", "inputBaz":"c"}
I am using the Jackson ObjectMapper to attempt to convert the JSON to my POJO. I know that the input baz String from the JSON wont map cleanly to the Set that I am trying to represent it as, so I defined a custom Deserializer:
public class MyDeserializer extends StdDeserializer<Set<String>> {
public MyDeserializer(){}
public MyDeserializer(Class<?> vc) {
super(vc);
}
public Set<String> deserialize(JsonParser p, DeserializationContext cxt) throws IOException, JsonProcessingException {
String input = p.readValueAs(String.class);
Set<String> output = new HashSet<>();
if(input != null) {
output.add(input);
}
return output;
}
}
I am getting an IllegalArgumentException referencing the "inputBaz" attribute, which I can provide details on. Does anyone see any obvious issue with my deserializer implementation? Thanks
You do not need to implement custom deserialiser, use ACCEPT_SINGLE_VALUE_AS_ARRAY feature. It works for sets as well:
Feature that determines whether it is acceptable to coerce non-array
(in JSON) values to work with Java collection (arrays,
java.util.Collection) types. If enabled, collection deserializers will
try to handle non-array values as if they had "implicit" surrounding
JSON array. This feature is meant to be used for
compatibility/interoperability reasons, to work with packages (such as
XML-to-JSON converters) that leave out JSON array in cases where there
is just a single element in array. Feature is disabled by default.
See also:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.ArrayList out of START_OBJECT token
Replace the 2 constructors with this no-arg constructor:
public MyDeserializer() {
super(TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class));
}
ACCEPT_SINGLE_VALUE_AS_ARRAY as suggested is a good option.
Maybe your actual problem is more complicated but if not you could also try #JsonCreator instead of custom deserializer. Like:
public class Example {
#JsonCreator
public Example(#JsonProperty("inputFoo") String foo,
#JsonProperty("inputBar") String bar,
#JsonProperty("inputBaz") String strBaz) {
this.foo = foo;
this.bar = bar;
this.baz = new HashSet<>();
baz.add(strBaz);
}
private String foo;
private String bar;
private Set<String> baz;
}
Just to show that in more general case you might avoid implementing custom deserializer with #JsonCreator also but still make some simple conversions.

How can we add transient to existing class using reflection in java?

Is there any way to make field static or transient using java reflection API.
EDIT: I have some Beans that are already being serialised using soap api and is being used by some clients, for some clients i don't want to expose one or two fields.
Sure there are so many ways to do it without changing or adding transient keyword.
Just want to know if it can be done, and if so, how ?
EDIT: I wouldn't call it an API or framework issue, more like a design flaw...
I'm using apache axis2 for soap
No. Such a thing would require modifying the byte code of the class. A particular difficulty in the case of static fields is that they are accessed using different bytecodes than object fields.
I don't see a why a field couldn't be made transient in runtime, at least in theory, but the current reflection API doesn't allow it. See also: Can a field's transient property/flag be set through reflection in java?
You can't do it with the reflection api. I think there are some byte-code manipulation tools but in this case you can use the Decorator pattern. It solves the problem but I think it is extremely ugly:
(I omited the usual boilerplate from here such as interfaces)
public class StaticDecorator {
private static Object staticField;
private Object yourObject;
public StaticDecorator(Object yourObject) {
this.yourObject = yourObject;
}
public static Object getStaticField() {
return staticField;
}
public static void setStaticField(Object object) {
staticField = object;
}
}
I used Object for the type of the class you are going to wrap but of course you can substitute any type you want. Using an approach like this you can "decorate" any class with a static field.
If you are really, extremely must want a static field in an object at run time this can help you but I think that there is a design flaw lurking somewhere.
You can wrap your bean inside another bean that only exposes the fields that you'd like to expose through your API. For example, with an internal bean with the fields foo, bar, and baz, where you do not want to expose baz.
Lombok Delegation can make this incredibly simple, but here's an example using plain-old-Java.
public class ExposedBean {
private InternalBean internalBean;
public ExposedBean(InternalBean internalBean) {
this.internalBean = internalBean;
}
public String getFoo() { return internalBean.getFoo(); }
public String getBar() { return internalBean.getBar(); }
}
public class InternalBean {
private String foo;
private String bar;
private String baz;
public String getFoo() { return foo; }
public String getBar() { return bar; }
public String getBaz() { return baz; }
}
Original answer, regarding setting modifiers
You can not set modifiers. You can check them, however.
Field myField = /* get a field object */;
if (Modifier.isTransient(myField.getModifiers()) {
System.out.println("myField is transient.");
}
if (Modifier.isFinal(MyClass.class.getModifiers()) {
System.out.println("MyClass is final.");
}
With more information about the problem you're trying to solve, we can suggest alternatives. Member#getModifiers() is not declared final, so you could possibly use a decorator. (The below code is 100% untested.)
public class FieldModifierDecorator extends Field {
protected Field field;
private int modifiers = -1;
public static void decorate(Field field) {
FieldModifierDecorator newInstance = new FieldModifierDecorator();
newInstance.field = field;
return newInstance;
}
public void overrideModifiers(int modifiers) {
this.modifiers = modifiers;
}
public int getModifiers() {
if (-1 == modifiers) {
return field.getModifiers();
}
return modifiers;
}
}
// Example usage
public Field makeFieldAppearTransient(Field field) {
FieldModifierDecorator decoratedField = FieldModifierDecorator.decorate(field);
decoratedField.overrideModifiers(field.getModifiers() | Modifier.TRANSIENT);
// if (Modifier.isTransient(decoratedField.getModifiers())) {
// System.out.println("It looks transient, but really isn't.");
//}
return decoratedField;
}
Modfifying class information or byte code modification is definitely the wrong tool for the job. You are trying to solve a business problem with solely technical tools.
It sounds more like you need a permission concept. Users may have permission to see some fields. Based on that you could use java bean introspection to clear the values of those fields just before they are sent to the client.
However this might have its problems as well. A client should be able to determine if it has permission to see that field or not.

Java: Access Fields without knowing their names. ("Save reference")

I need to get a Field (or a list of Fields) without knowing it's name.
I.e: for a custom entitymanager i'd like to be able to do Method Calls like this:
cem.getEntities(MyEntity.class, ParamMap) where the ParamMap should be of the Type Map<Field, Object>.
What i can do at the moment is something like this:
Map<Field, Object> params = new HashMap<Field, Object>();
params.put(MyEntity.class.getDeclaredField("someFieldName"), 20);
List<MyEntity> entitysWithSomeFieldNameEquals20 = cem.getEntities(MyEntity.class, params);
Im trying to avoid the usage of querys, because it should work "generic" in the first place, but also be independent from Strings. (They are error-prone). The Entity Manager therefore uses reflection to determine the table and column names, he needs to use.
However, I STILL need to use
MyEntity.class.getDeclaredField("someFieldName")
which will simple move the error-prone string "out" of the entity manager...
What i'm trying to achieve would be something like this:
MyEntity.class.getDeclaredField(MyEntity.class.fields.someFieldName.toString())
So, no matter what the actual field is named, it can be referenced in a save way and refactoring will refactor all the field-access calls, too.
I'm not sure if this is possible. I could go with a (encapsuled) enum for ALL entities, but I hope, that theres a more generic way to achieve this.
Edit:
One good solution seems to be the usage of constants:
public class MyEntity{
private static string SOME_FIELD = "some_field_name_in_database";
#Column(name = SOME_FIELD);
private String someField;
}
...
Map<String, Object> params = new HashMap<String, Object>();
params.put(MyEntity.SOME_FIELD, matchValue);
List<MyEntity> result = eem.getEntities(MyEntity.class, params);
This at least reduces the usage of the string to exactly one location, where it can be maintained and changed without affecting any other file. But im still searching for a solution without constants, so the contants don't need to be synchronized with the available fields :-)
Ok, this is just an idea, which is not easy to implement, but it could work.
Suppose MyEntity looks like this:
public class MyEntity {
private String foo;
private String bar;
public String getFoo() { return this.foo; }
public void setFoo(String foo) { this.foo = foo; }
public String getBar() { return this.bar; }
public void setBar(String bar) { this.bar = bar; }
}
and there is an interface:
public interface Pattern {
public Class<?> getEntityClass();
public Map<Field, Object> getFields();
}
and there is a method, which takes a class and generates a pattern object, which is an instance of the given class:
public class PatternFactory {
public <T> T createPattern(Class<T> klass) {
// magic happens here
}
}
The requirement for the emitted instance would be that it should implement the Pattern interface, such that the method getFields returns only the fields which were explicitly set. GetEntityClass should return the entity class. Then the custom entity manager could be implemented like this:
public class EntityManager {
public <T> Collection<T> getEntities(T pattern) {
if (!(pattern instanceof Pattern))
throw new IllegalArgumentException();
Class<?> klass = ((Pattern) pattern).getEntityClass();
Map<Field, Object> fields = ((Pattern) pattern).getFields();
// fetch objects here
}
}
Then you could use it like this:
PatternFactory pf = // obtain somehow
EntityManager em = // obtain somehow
MyEntity pattern = pf.createPattern(MyEntity.class);
pattern.setFoo("XYZ");
pattern.setBar(null);
Collection<MyEntity> result = em.getEntities(pattern);
In this case pattern.getFields would return a map with two entries.
The difficulty here lies, of course, in the implementation of the createPattern method, where you will have to emit bytecode at run-time. However, this is possible and can be done.

Handling more than 7 Parameters

I have a public class, which needs 7 parameters to be passed down. At the moment, I am able to make 3 of them being passed to constructor and another 4 to a public method in the class . Like this:
Public Class AClass{
private XClass axClass;
private String par4;
private String par5;
private String par6;
private String par7;
public AClass(String par1, String par2, String par3){
aXClass = new XClass(par1,par2,par3);
}
public execute(String par4,String par5, String par6, String par7){
//this is needed because they are used in other private methods in this class
this.par4 = par4;
this.par5 = par5;
this.par6 = par6;
this.par7 = par7;
//call other private methods within this class.
//about 7 lines here
}
}
My question is, is this the right way to ask client of the class to passing in paramters?
There shouldn't be anything stopping you from passing 7 parameters to a constructor, if that's what you want. I don't know if there's a maximum number of parameters that can be passed to a method in Java, but it's certainly higher than 7 if there is a max.
When you create a class and its public methods, you're creating an interface on how to use and access that class. So technically what you've done so far is correct. Is it the "right way" to ask the client of a class to pass in arguments? That's up to you, the designer of the interface.
My first instinct when I saw 7 parameters being passed was to silently ask "Is there some relationship between some or all of these parameters that might mean they'd go together well in a class of their own?" That might be something you address as you look at your code. But that's a question of design, not one of correctness.
I'd go for the Builder Pattern instead of many constructor parameters as suggested by
Effective Java Item 2: Consider a builder when faced with many constructor parameters
Here's a simple class to illustrate:
public class Dummy {
private final String foo;
private final String bar;
private final boolean baz;
private final int phleem;
protected Dummy(final Builder builder) {
this.foo = builder.foo;
this.bar = builder.bar;
this.baz = builder.baz;
this.phleem = builder.phleem;
}
public String getBar() {
return this.bar;
}
public String getFoo() {
return this.foo;
}
public int getPhleem() {
return this.phleem;
}
public boolean isBaz() {
return this.baz;
}
public static class Builder {
private String foo;
private String bar;
private boolean baz;
private int phleem;
public Dummy build() {
return new Dummy(this);
}
public Builder withBar(final String bar) {
this.bar = bar;
return this;
}
public Builder withBaz(final boolean baz) {
this.baz = baz;
return this;
}
public Builder withFoo(final String foo) {
this.foo = foo;
return this;
}
public Builder withPhleem(final int phleem) {
this.phleem = phleem;
return this;
}
}
}
You would instantiate it like this:
Dummy dummy = new Dummy.Builder()
.withFoo("abc")
.withBar("def")
.withBaz(true)
.withPhleem(123)
.build();
The nice part: you get all the benefits of constructor parameters (e.g. immutability if you want it), but you get readable code too.
Can't you just make a class/hashmap that stores these parameters and pass this to the function?
public excute(Storageclass storageClass){
//this is needed because they are used in other private methods in this class
this.par4 = storageClass.getPar4();
this.par5 = storageClass.getPar5();
this.par6 = storageClass.getPar6();
this.par7 = storageClass.getPar7();
//or
this.storageClass = storageClass;
}
I don't really see the problem with that.
In any case you could create a "Request" object or something like this:
class SomeClass {
private String a;
private String b;
....
public SomeClass( Request r ) {
this.a = r.get("a");
this.b = r.get("b");
...
}
public void execute( Request other ) {
this.d = other.get("d");
this.e = other.get("d");
...
}
}
See also: http://c2.com/cgi/wiki?TooManyParameters
Without knowing the use of the child class, I can say that there is nothing inherently wrong with what you have done.
Note though that you have to declare
private XClass axClass;
in the variables of your AClass.
However, you say 'I am able to make....' Does this mean there is some problem with declaring this another way?
I don't care for it much, because an object should be 100% ready to be used after its constructor is called. It's not as written in your example.
If the parameters passed into the execute method can simply be consumed, and that's the method of interest for clients, I see no reason for them to be data members in the class.
Without knowing more about your ultimate aims it's hard to tell. But I would re-think this implementation.
If you're planning on introducing an AClass.someMethod() that needs to know par4-7 without requiring you to have called AClass.excute(), then clearly you should be passing the parameters in the constructor.
On the other hand: if you can construct an instance of this object with only par1-3 and do something meaningful with it besides call excute() then it makes sense to allow the object to be constructed with fewer than the full seven parameters.
Yet my own aesthetic is to try and limit the number of "modes" that an object can be in which make certain methods work and others fail. So ideally, a fully-constructed object is ready to run any method the programmer might call. I'd worry about the design issue more than be too concerned about the sheer number of parameters to the constructor.
But as others have pointed out, sometimes there is a natural grouping of these parameters which can deserve objects of their own. For instance: in many APIs instead of passing (x, y, width, height) all over the place they use rectangle objects.
As others already wrote, it is technically correct to pass 7 parameters, although not very 'user-friendly', if you can say so.
Since you didn't write much about this class, I can suggest one small thing: in constructor you're just creating XClass object, so it would be sane to create this object before and pass it as a single parameter.
Something like this:
...
XClass aXClass = new XClass(par1, par2, par3);
AClass aClass = new AClass(aXClass);
...
And this is the constructor:
public AClass(XClass aXClass) {
this.aXClass = aXClass;
}

Categories

Resources