builder pattern json deserialize - java

I have a problem. I just used the example of jackson json for deserializing builder pattern but I always get an empty json.
I use jackson-databind version 2.8.4
Am I missing something?
So my code is as follows:
The Value class
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
#JsonDeserialize(builder=ValueBuilder.class)
public class Value {
private final int x, y;
protected Value(int x, int y) {
this.x = x;
this.y = y;
}
}
The ValueBuilder Class
import com.fasterxml.jackson.annotation.JsonCreator;
//#JsonPOJOBuilder(buildMethodName = "build", withPrefix = "with")
public class ValueBuilder {
private int x;
private int y;
// can use #JsonCreator to use non-default ctor, inject values etc
public ValueBuilder() { }
// if name is "withXxx", works as is: otherwise use #JsonProperty("x") or #JsonSetter("x")!
public ValueBuilder withX(int x) {
this.x = x;
return this; // or, construct new instance, return that
}
public ValueBuilder withY(int y) {
this.y = y;
return this;
}
#JsonCreator
public Value build() {
return new Value(x, y);
}
}
The Start Class
public class Start {
public static void main(String[] args) throws IOException {
Value newValue = new ValueBuilder().withX(2).withY(4).build();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(newValue);
System.out.println(jsonString);
}
}

You're only missing accessible getters for x and y in your Value class - the ObjectMapper requires access to those in order to serialize.
Add the following to your Value class definition:
public int getX() {
return x;
}
public int getY() {
return y;
}
No need for additional annotations in this context.
Your JSON will print out like:
{"x":2,"y":4}
You could also make the fields public to reach the same result, but that would defile proper encapsulation.

Related

Map with custom key in Groovy vs Java

I want to use a map in Groovy where the keys will be instances of an unmutable class.
This is something I do often in Java and it works fine, like in this example class:
public class TestMap {
static final class Point {
final int x; final int y;
public Point(int x, int y) {this.x = x;this.y = y;}
}
public static void main(String[] args) {
Map<Point, String> map = new HashMap<>();
final Point origin = new Point(0, 0);
map.put(origin, "hello world !" );
if(!map.containsKey(origin))
throw new RuntimeException("can't find key origin in the map");
if(!map.containsKey(new Point(0,0))) {
throw new RuntimeException("can't find new key(0,0) in the map");
}
}
}
But when I try to achieve the same thing with Groovy, it doesn't work.
Why ?
Here is a sample non working example in Groovy:
class Point {
final int x; final int y
Point(int x, int y) { this.x = x; this.y = y }
public String toString() { return "{x=$x, y=$y}" }
}
def origin = new Point(0, 0)
def map = [(origin): "hello"]
map[(new Point(1,1))] = "world"
map.put(new Point(2,2), "!")
assert map.containsKey(origin) // this works: when it's the same ref
assert map.containsKey(new Point(0,0))
assert map.containsKey(new Point(1,1))
assert map.containsKey(new Point(2,2))
assert !map.containsKey(new Point(3,3))
You need to have an equals and hashCode method on your Point class so that the instances can be found as keys in the HashMap
You can do this quickly by adding an annotation in Groovy:
import groovy.transform.*
#EqualsAndHashCode
class Point {
final int x; final int y
Point(int x, int y) { this.x = x; this.y = y }
public String toString() { return "{x=$x, y=$y}" }
}

How to deserialize from json tree?

Suppose I have json tree already read.
Is it possible to deserialize from it (without converting back to string)?
public class TryDeserializeNode {
public static class MyClass {
private int x = 11, y = 12;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
MyClass myClass = new MyClass();
String string = mapper.writeValueAsString(myClass);
JsonNode tree = mapper.readTree(string);
// how to deserialize from tree directly?
// MyClass myclass2 = mapper.readValue(tree.toString(), MyClass.class);
MyClass myclass2 = mapper.readValue(tree, MyClass.class);
}
}
You could simply use treeToValue:
MyClass myclass2 = mapper.treeToValue(tree, MyClass.class);
where mapper is your Jackson mapper and tree is your JsonNode.

Generic behaviour

(sorry for the pun)
Say one wants to define a generic builder, like this:
public abstract class GenericBuilder<T extends Product> {
int x;
int y;
<K extends GenericBuilder<T>> K setX(int x) {
this.x = x;
return (K)this;
}
<K extends GenericBuilder<T>> K setY(int y) {
this.y = y;
return (K) this;
}
abstract T build();
}
abstract class Product {
int x;
int y;
}
class ConcreteProduct extends Product {
int z;
}
class ConcreteBuilder extends GenericBuilder<ConcreteProduct>{
int z;
<K extends GenericBuilder<ConcreteProduct>> K setZ(int z) {
this.z = z;
return (K) this;
}
#Override
ConcreteProduct build() {
ConcreteProduct cp = new ConcreteProduct();
cp.x = x;
cp.y = y;
cp.z = z;
return cp;
}
public static void main(String[] args) {
new ConcreteBuilder().setX(1).setY(2).setZ(3);
}
}
When calling ConcreteBuilder.setZ(), it fails during compilation.
Why is that? Is it due erasure? Or the generics, say, don't carry information about its generic parameters?
EDIT:
Any ideas how to avoid using second generic parameter in:
public class ConcreteBuilder extends GenericBuilder<ConcreteProduct, ConcreteBuilder>
i.e. <..., ConcreteBuilder>, which seems to be a little clumsy? I guess it's not possible. Are there other languages (C# maybe?) which allow to do that?
Break your code this way and you will understand that your class GenericBuilder<ConcreteProduct> doesn't have any setZ() method defined.
GenericBuilder<ConcreteProduct> setY = new ConcreteBuilder().setX(1).setY(2);
setY.setZ(3);
In your GenericBuilder your functions return a GenericBuilder when you don't specify the type argument of the function. In your main function the call to setX returns a GenericBuilder and you loose the information that you are actually using a ConcreteBuilder. To succesfully make the calls, you have to specify the generic parameters for the setters:
new ConcreteBuilder().<ConcreteBuilder>setX(1).<ConcreteBuilder>setY(2).setZ(3);
Alternative
You can add a second type parameter to GenericBuilder:
public abstract class GenericBuilder<T extends Product, K extends GenericBuilder<T, K>> {
int x;
int y;
K setX(int x) {
this.x = x;
return (K)this;
}
K setY(int y) {
this.y = y;
return (K) this;
}
abstract T build();
}
and change ConcreteBuilder to this:
public class ConcreteBuilder extends GenericBuilder<ConcreteProduct, ConcreteBuilder> {
int z;
ConcreteBuilder setZ(int z) {
this.z = z;
return this;
}
#Override
public ConcreteProduct build() {
ConcreteProduct cp = new ConcreteProduct();
cp.x = x;
cp.y = y;
cp.z = z;
return cp;
}
public static void main(String[] args) {
new ConcreteBuilder().setX(1).setY(2).setZ(3);
}
}

Copy pojo fields to another pojo's setters

Let's say I have class A with public fields x and y. And let's say I have another pojo class B but that uses setters and getters, so it has setX() and setY().
I'd like to use some automatic way to copy from instance of A to B and back.
With default settings at least, Dozer's
Mapper mapper = new DozerBeanMapper();
B b = mapper.map(a, B.class);
does not copy the fields correctly.
So is there a simple configuration change that allows me to accomplish the above with Dozer, or another library that would do this for me?
I'd suggest you use:
http://modelmapper.org/
Or take a look at this question:
Copy all values from fields in one class to another through reflection
I'd say that both API's (BeanUtils) and ModelMapper provide one-liners for copy pojos' values to another pojos. Take a look # this:
http://modelmapper.org/getting-started/
Not actually a one-liner but this approach doesn't require any libs.
I was testing it using these classes:
private class A {
public int x;
public String y;
#Override
public String toString() {
return "A [x=" + x + ", y=" + y + "]";
}
}
private class B {
private int x;
private String y;
public int getX() {
return x;
}
public void setX(int x) {
System.out.println("setX");
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
System.out.println("setY");
this.y = y;
}
#Override
public String toString() {
return "B [x=" + x + ", y=" + y + "]";
}
}
To get public field we can use reflection, as for setters it's better to use bean utils:
public static <X, Y> void copyPublicFields(X donor, Y recipient) throws Exception {
for (Field field : donor.getClass().getFields()) {
for (PropertyDescriptor descriptor : Introspector.getBeanInfo(recipient.getClass()).getPropertyDescriptors()) {
if (field.getName().equals(descriptor.getName())) {
descriptor.getWriteMethod().invoke(recipient, field.get(donor));
break;
}
}
}
}
The test:
final A a = new A();
a.x = 5;
a.y = "10";
System.out.println(a);
final B b = new B();
copyPublicFields(a, b);
System.out.println(b);
And its output is:
A [x=5, y=10]
setX
setY
B [x=5, y=10]
For someone who is still looking for,
You could try this using Gson
Gson gson = new Gson();
Type type = new TypeToken<YourPOJOClass>(){}.getType();
String data = gson.toJson(workingPOJO);
coppiedPOJO = gson.fromJson(data, type);

Is there a way to ensure at compile time that certain fields in an immutable object are set whilst keeping role of the arguments clear?

I'm experimenting with ways of creating immutable objects. The following builder objects
are quite attractive because they keep the role of the arguments clear. However I would like
to use the compiler to verify that certain fields are set, like with the Immutable() constructor invocation. StrictImmutableBuilder provides those checks, but is rather noisy. Is there some way to get the same checks but with the form of LaxImmutableBuilder? Perhaps using annotations?
public class Immutable {
public static void main(String[] args) {
new Immutable("13272873C", 23, false);
// nice but what where those arguments?
new LaxImmutableBuilder() {{
refCode("13272873C");
age(23);
subscribed(false);
}}.build();
// now I know what each value represents
// but what if I forgot to set one?
new StrictImmutableBuilder() {
public String refCode() { return "13272873C"; }
public int age() { return 23; }
public boolean subscribed() { return false; }
}.build();
// now I'm forced to set each field, but now
// we have the extra noise of "return"
// and also "public" if we want to use
// this outside the current package
// is there another way? maybe using annotations?
}
private final String refCode;
private final int age;
private final boolean subscribed;
public String getRefCode() {
return refCode;
}
public int getAge() {
return age;
}
public boolean isSubscribed() {
return subscribed;
}
public Immutable(String a, int b, boolean c) {
this.refCode = a;
this.age = b;
this.subscribed = c;
}
}
abstract class StrictImmutableBuilder {
public abstract String refCode();
public abstract int age();
public abstract boolean subscribed();
public Immutable build() {
return new Immutable(refCode(), age(), subscribed());
}
}
abstract class LaxImmutableBuilder {
private String refCode;
private int age;
private boolean subscribed;
protected void refCode(String refCode) {
this.refCode = refCode;
}
protected void age(int age) {
this.age = age;
}
protected void subscribed(boolean subscribed) {
this.subscribed = subscribed;
}
public Immutable build() {
return new Immutable(refCode, age, subscribed);
}
}
Here's the pattern I use:
class YourClass {
// these are final
private final int x;
private final int y;
private int a;
private int b;
// finals are passed into the constructor
private YourClass(int x, int y) {
this.x = x;
this.y = y;
}
public static class Builder {
// int x, int y, int a, int b
// whatever's final is passed into constructor
public Builder(int x, int y) {
this.x = x;
this.y = y;
}
// a and b are optional, so have with() methods for these
public Builder withA(int a) {
this.a = a;
return this;
}
public Builder withB(int b) {
this.b = b;
return this;
}
public YourClass build() {
YourClass c = new YourClass (x, y);
c.a = a;
c.b = b;
return c;
}
}
}
there is this trick: Type-safe Builder Pattern
http://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/
but that's just too crazy.

Categories

Resources