How do I programmatically set custom converter for dozer? The following code doesn't work:
Custom Converter implementation:
class ConverterImpl extends DozerConverter<A, B> {
ConverterImpl() {
super(A.class, B.class);
}
#Override
public B convertTo(A source, B destination) {
return destination;
}
#Override
public A convertFrom(B source, A destination) {
return destination;
}
}
Test code:
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.setCustomConverters(Collections.<CustomConverter>singletonList(new ConverterImpl()));
A a = new A();
B b = mapper.map(a, A.class);
After running the code above, custom converter doesn't get invoked. What is wrong?
Looks like you have to actually add a specific mapping, and unfortunately you can only specify field-level converters, not class-level converters, using the programmatic API. So if you wrap the A and B classes in container classes, you can specify a mapping for the A and B fields.
For example the following verbose code works as expected:
public class DozerMap {
public static class ContainerA {
private A a;
public A getA() { return a; }
public void setA(A a) { this.a = a; }
}
public static class ContainerB {
private B b;
public B getB() { return b; }
public void setB(B b) { this.b = b; }
}
private static class A { };
private static class B { };
static class ConverterImpl extends DozerConverter<A, B> {
ConverterImpl() {
super(A.class, B.class);
}
#Override
public B convertTo(A source, B destination) {
Logger.getAnonymousLogger().info("Invoked");
return destination;
}
#Override
public A convertFrom(B source, A destination) {
Logger.getAnonymousLogger().info("Invoked");
return destination;
}
}
public static void main(String[] args) {
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.setCustomConverters(Collections.<CustomConverter> singletonList(new ConverterImpl()));
BeanMappingBuilder foo = new BeanMappingBuilder() {
#Override
protected void configure() {
mapping(ContainerA.class, ContainerB.class).fields("a", "b", FieldsMappingOptions.customConverter(ConverterImpl.class));
}
};
mapper.setMappings(Collections.singletonList(foo));
ContainerA containerA = new ContainerA();
containerA.a = new A();
ContainerB containerB = mapper.map(containerA, ContainerB.class);
}
}
Why do you want to set it programatically ? I mean do you have any specific needs ? Otherwise, Mapping via an xml file works fine.
In case you want to do it more in a programing way , rather through some xml configuration files, Check out Orika.
It has good API support.
Related
I have some generated code (i.e. it cannot be changed) that looks something like this.
class Generated1 {
public String getA() {
return "1";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
class Generated2 {
public String getA() {
return "2";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
I am exploring these objects by reflection. None of them implement any common interface but there's many of them and I want to treat them as if they implement:
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
It certainly should be possible. This is considered perfectly good code
class CommonInterface1 extends Generated1 implements CommonInterface {
// These are perfectly good classes.
}
class CommonInterface2 extends Generated2 implements CommonInterface {
// These are perfectly good classes.
}
I suppose what I'm looking for is something like:
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(object);
}
}
My question: How do I treat an object that doesn't implement an interface but actually has all the code to do so as if it does implement the interface.
I want to replace
private void doCommon(Generated1 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void doCommon(Generated2 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
...
with
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
I know I can use a Proxy like this but I'd really prefer to use something better.
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(adapt(object));
}
}
private CommonInterface adapt(Object o) {
return adapt(o, CommonInterface.class);
}
public static <T> T adapt(final Object adaptee,
final Class<T>... interfaceToImplement) {
return (T) Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
interfaceToImplement,
// Call the equivalent method from the adaptee.
(proxy, method, args) -> adaptee.getClass()
.getMethod(method.getName(), method.getParameterTypes())
.invoke(adaptee, args));
}
If you're using reflection, you don't need the two CommonInterfaceX classes, you can use a proxy implementing CommonInterface:
public class Wrapper implements InvocationHandler {
private final Object delegate;
public static <T> T wrap(Object obj, Class<T> intf) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
new Wrapper(obj));
return intf.cast(proxy);
}
private Wrapper(Object delegate) {
this.delegate = delegate;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method dmethod = delegate.getClass().getMethod(
method.getName(), method.getParameterTypes());
return dmethod.invoke(delegate, args);
}
}
You can use this class as follows:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
UPDATE: note that the same Wrapper class works with any interface.
There's no way to achieve a static type relationship between Generated1 and Generated2.
Even if you created CommonInterface1 and CommonInterface2, you still wouldn't be able to statically use a Generated1 object as a CommonInterface1 because new Generated1() is not a CommonInterface1 (and will never become one)
By far the simplest solution is to change your code generation to add the CommonInterface to Generated1 and Generated2.
If that's absolutely impossible, the only other way to avoid this code duplication is to go for reflection.
You can do it manuallly by reflection.
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
Output is
getA() = A
sayHello("Max") = hello Max
If you want to replace as your comment. I think you can do it easily
First, you create interface CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
After that, you create 2 class Generated1 and Generated2 inherited CommonInterface
class Generated1 implements CommonInterface {
#overide
public String getA() {
return "1";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
#overide
public String getA() {
return "2";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
I want to implement Builder Pattern with inheritance. So I have 4 following classes: one abstract class (ClassA), ClassB, ClassC. TestTest class is used to see how all this works:
public abstract class ClassA {
private String aString;
public String getaString() {
return aString;
}
public abstract class ClassABuilder<T extends ClassABuilder>{
public T setaString(String str) {
ClassA.this.aString = str;
return (T)this;
}
public abstract ClassA build();
}
}
public class ClassB extends ClassA{
private String bString;
public String getbString() {
return bString;
}
public class ClassBBuilder<T extends ClassBBuilder> extends ClassA.ClassABuilder<T>{
public T setbString(String str) {
ClassB.this.bString = str;
return (T)this;
}
#Override
public ClassB build(){
return ClassB.this;
}
}
}
public class ClassC extends ClassB{
private String cString;
public String getcString() {
return cString;
}
public static ClassCBuilder<ClassCBuilder> newBuilder(){
return new ClassC().new ClassCBuilder();
}
public class ClassCBuilder<T extends ClassCBuilder> extends ClassB.ClassBBuilder<T>{
public T setcString(String str) {
ClassC.this.cString = str;
return (T)this;
}
#Override
public ClassC build(){
return ClassC.this;
}
}
}
public class TestTest {
public static void main(String[] args) {
// TODO code application logic here
ClassC C=ClassC.newBuilder()
.setaString(null)
.setbString(null)
.setcString(null) //LINE XXX
.build();
}
}
The problem is that at TestTest at LINE XXX I get can't find symbol "setcString". What do I do wrong?
Let's track it down along the hierarchy:
First consider this signature:
class ClassABuilder<T extends ClassABuilder>
When you call setaString(null) the returned T will be an object that extends ClassABuilder. The compiler knows that this is a ClassBBuilder and thus will allow you to call setbString(null).
However, since the definition states T is required to extend a raw ClassBBuilder only any information on ClassBBuilder's generic types will be lost. Thus the compiler only knows that T is a ClassBBuilder but not that it's actually a ClassCBuilder which extends ClassBBuilder<ClassCBuilder> and hence doesn't know about setcString() on the returned type.
As has already been mentioned, using T extends ClassABuilder<T> will fix that since now the compiler knows there's another generic type to be passed down the hierarchy.
newBuilder() would then have to look like this:
public static ClassCBuilder<?> newBuilder(){
//you have too create a raw type here so you'll have to ignore/suppress/live with the warning
return (new ClassC().new ClassCBuilder());
}
As #AndyTurner already observed, the problem is that you use raw versions of your builder class types as type parameters. He did not go into detail, but the upshot is this:
ClassC C=ClassC.newBuilder() // yields a ClassCBuilder<ClassCBuilder>
.setaString(null) // yields a raw ClassCBuilder (type parameter)
.setbString(null) // yields a raw ClassBBuilder (type parameter bound)
.setcString(null) // ERROR: no such method on ClassBBuilder
.build();
To fix this with minimal change to your class structure and strategy, you must not only correct the type parameter bounds for your builder classes, as Andy advised ...
ClassABuilder<T extends ClassABuilder<T>>
... etc., but also make a change to ClassC.newBuilder(), such as to make it generic:
public static <T extends ClassCBuilder<T>> ClassCBuilder<T> newBuilder() {
return new ClassC().new ClassCBuilder<T>();
}
With that combination of changes, your code compiles for me.
I would like to post here the test demonstrating builder pattern with deep inheritance.
class TypeParamTest {
#Test
void test() {
Dd dd = Dd.builder()
.setIntAa(0)
.setIntBb(1)
.setIntCc(2)
.setIntDd(3)
.build();
assertEquals(0, dd.intAa);
assertEquals(1, dd.intBb);
assertEquals(2, dd.intCc);
assertEquals(3, dd.intDd);
}
abstract static class Aa {
int intAa;
static class AaBuilder<B extends AaBuilder> {
int intAa;
Aa build(Aa aa) {
aa.intAa = intAa;
return aa;
}
B setIntAa(int i) {
this.intAa = i;
return (B) this;
}
}
}
abstract static class Bb extends Aa {
int intBb;
static class BbBuilder<B extends BbBuilder<B>>
extends AaBuilder<B>
{
int intBb;
Bb build(Bb bb) {
bb = (Bb) super.build(bb);
bb.intBb = intBb;
return bb;
}
B setIntBb(int i) {
this.intBb = i;
return (B) this;
}
}
}
static class Cc extends Bb {
int intCc;
static CcBuilder<?> builder() {
return new CcBuilder<>();
}
static class CcBuilder<B extends CcBuilder<B>>
extends BbBuilder<B>
{
int intCc;
Cc build() {
return build(new Cc());
}
Cc build(Cc cc) {
cc = (Cc) super.build(cc);
cc.intCc = intCc;
return cc;
}
B setIntCc(int i) {
this.intCc = i;
return (B) this;
}
}
}
static class Dd extends Cc {
int intDd;
static DdBuilder<?> builder() {
return new DdBuilder<>();
}
static class DdBuilder<B extends DdBuilder<B>>
extends CcBuilder<B>
{
int intDd;
Dd build() {
return build(new Dd());
}
Dd build(Dd dd) {
dd = (Dd) super.build(dd);
dd.intDd = intDd;
return dd;
}
B setIntDd(int i) {
this.intDd = i;
return (B) this;
}
}
}
}
I'm trying to do a simple example of deserializing json into polymorphic classes. The deserialization fails with the error:
org.codehaus.jackson.map.JsonMappingException: Could not resolve type id 'aField' into a subtype of [simple type, class ...SubClassA]
If I try the deserialization for a single subclass, just using the JSON for that class, it succeeds, but when I put the two classes together inside the SubClassTestObject, it fails. Any ideas for fixing this? Do I need to write a custom deserializer?
Here is my JSON:
{
"classA":{
"aField":"A",
"baseField":"baseA"
},
"classB":{
"baseField":"baseB",
"bField":"B"
}
}
Here are my classes:
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
#JsonSubTypes({
#JsonSubTypes.Type(value = SubClassA.class, name = "classA"),
#JsonSubTypes.Type(value = SubClassB.class, name = "classB")
})
#JsonIgnoreProperties(ignoreUnknown = true)
public abstract class AbstractSimpleClass {
String baseField;
public String getBaseField() {
return baseField;
}
public void setBaseField(String baseField) {
this.baseField = baseField;
}
}
public class SubClassA extends AbstractSimpleClass {
String aField;
public String getaField() {
return aField;
}
public void setaField(String aField) {
this.aField = aField;
}
}
public class SubClassB extends AbstractSimpleClass {
String bField;
public String getbField() {
return bField;
}
public void setbField(String bField) {
this.bField = bField;
}
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class SubClassTestObject {
#JsonProperty("classA")
SubClassA a;
#JsonProperty("classB")
SubClassB b;
public SubClassA getA() {
return a;
}
public void setA(SubClassA a) {
this.a = a;
}
public SubClassB getB() {
return b;
}
public void setB(SubClassB b) {
this.b = b;
}
}
And here is my test:
#Test
public void testBoth() throws IOException, URISyntaxException {
ClassLoader classLoader = getClass().getClassLoader();
json = new String(Files.readAllBytes(Paths.get(classLoader.getResource("test/so-example.json").toURI())));
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(SubClassA.class, SubClassB.class);
SubClassTestObject testObj = mapper.readValue(json, SubClassTestObject.class); //Fails here
SubClassA a = testObj.getA();
SubClassB b = testObj.getB();
assertTrue(a.getBaseField().equals("baseA"));
assertTrue(b.getBaseField().equals("baseB"));
assertTrue(a.getaField().equals("A"));
assertTrue(b.getbField().equals("B"));
}
After your edit:
This
#JsonProperty("classA")
SubClassA a;
is completely unrelated to
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
The JsonTypeInfo.As.WRAPPER_OBJECT is meant to be implicit. It's not something you map in your POJOs. You won't be able to map your current JSON with this strategy. Either do what's below or change your JsonTypeInfo to use a JsonTypeInfo.As.PROPERTY for example, then provide the corresponding #type (and its appropriate value) property in the JSON.
Pre-edit:
Your SubClassTestObject class has two properties, a and b, because of
public SubClassA getA() {
return a;
}
public SubClassB getB() {
return b;
}
These aren't present in your JSON. And since you told Jackson to ignore unknown properties, it doesn't fail to deserialize. However, both of them are going to be left uninitialized.
The JSON you meant to deserialize is
{
"a": {
"classA": {
"aField": "A",
"baseField": "baseA"
}
},
"b": {
"classB": {
"baseField": "baseB",
"bField": "B"
}
}
}
which has a and b for your root SubClassTestObject object. And those use wrapper objects with the appropriate JsonTypeInfo name.
Structure
-ClassA
|---|
|---ClassAImplA
|---ClassAImplB
-Main
Class A:
public interface ClassA {
public void execute();
}
Implementaion A:
public class ClassAImplA implements ClassA
{
private int a = 5;
public ClassAImplA (int a){setA(a);}
#Override
public void execute() {
System.out.println(a);
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
Implementaion B:
public class ClassAImplB implements ClassA
{
private boolean b = false;
public ClassAImplB (int a){setB(b);}
#Override
public void execute() {
System.out.println(b);
}
public booelan getB() {
return b;
}
public void setA(boolean b) {
this.b = b;
}
main:
public class main {
/**
* #param args
*/
public static void main(String[] args) {
ClassAImplA param1 = new ClassAImplA(10);
ClassA = param1;
}
}
By doing this I make ClassA interchangeable,
but I lose the capability to access the parameter int a.
Is there a way to still make it interchangeable, and still have access to int a,
or in case of ClassAImplB, the field boolean b ?
There is a way, but it's not a good idea to do, as it defeats the purpose:
ClassAImplA param1 = new ClassAImplA(10);
ClassA = param1;
if (param1 instanceof ClassAImplA) {
param1x = (ClassAImplA) param1;
System.out.println(param1x.getA());
}
But don't do this. It defeats the purpose of the pattern.
The purpose of the pattern is to use objects of type ClassA,
without having to know how they work.
The getA method is only defined in ClassAImplA,
it's an implementation detail that should not be relevant to users of the ClassA type.
They shouldn't have to know. It's hidden.
This is called good encapsulation and information hiding.
you need one more class using composition to decide which implementation is needed.
public ClassHelper{
private A a;
public ClassHelper(A a){
this.a = a;
}
public void execute() {
this.a.execute();
}
}
public class main {
/**
* #param args
*/
public static void main(String[] args) {
ClassHelper param1 = new ClassHelper(new ClassAImplA(10));
param1.execute();
//or when you need classBIMpl
param1 = new ClassHelper(new ClassAImplB(true));
param1.execute();
}
}
And about the ability to access member of implA or implB , no you cannot have that flexibilty with this patter, whole point of this pattern is that caller need not be aware of implementation details.
Define an interface for the strategy and a Factory with different overloaded methods to create the concrete instances of the classes. Of course the methods are typed to the interface instead of the concrete classes.
The interface.
public interface Strategy {
void execute();
}
The first implementation.
public class ConcreteStrategy implements Strategy {
private boolean a;
public ConcreteStrategy(final boolean a) { this.a = a; }
public void execute() {}
}
The second implementation.
public class AnotherConcreteStrategy implements Strategy {
private int a;
public AnotherConcreteStrategy(final int a) { this.a = a; }
public void execute() {}
}
The factory.
public class Factory {
public static Strategy create(final boolean a) {
return new ConcreteStrategy(a);
}
public static Strategy create(final int a) {
return new AnotherConcreteStrategy(a);
}
}
How do you initialize this:
class A {
final B b;
A(B b) {
this.b = b;
}
}
class B {
final A a;
B(A a) {
this.a = a;
}
}
DI framework, reflection, better design?
Motivation and a use case (added):
My particular use case is simplifying field access in A's and B's sub-classes. So I'm injecting them to shortly reference them by fields in the derived classes without a need to declare explicitly in each sub-class.
There is also a recommendation on DI that objects should better be immutable: Guice best practices and anti-patterns.
You could use a factory method
class A {
final B b;
A(B b) {
this.b = b;
}
}
abstract class B {
final A a;
B() {
this.a = constructA();
}
protected abstract A constructA();
}
public class C {
public static void main(String []args){
new B(){
protected A constructA(){
return new A(this);
}
};
}
}
Though it may look dirty, but I prefer to replace one of the final references with Supplier (like one in Guava or Java 8) like:
class A {
final Supplier<B> b;
A(Supplier<B> b) {
this.b = b;
}
// keeping this constructor just for usability's sake
A(B b) {
this.b = ofInstance(b); // using Guava's Suppliers.ofInstance here
}
}
class B {
final A a;
B(A a) {
this.a = a;
}
}
public static void main(String[] args) {
// using MutableSupplier.create() static factory method
MutableSupplier<B> bRef = create();
A a = new A(bRef);
B b = bRef.set(new B(a));
}
where MutableSupplier looks somehow like the following:
import com.google.common.base.Supplier;
public class MutableSupplier<T> implements Supplier<T> {
private boolean valueWasSet;
private T value;
private MutableSupplier() {
}
#Override
public T get() {
if (!valueWasSet) {
throw new NullPointerException("Value has not been set yet");
}
return value;
}
public T set(final T value) {
if (valueWasSet) {
throw new IllegalStateException("Value has already been set and should not be reset");
}
this.value = value;
this.valueWasSet = true;
return value;
}
public static <T> MutableSupplier<T> create() {
return new MutableSupplier<T>();
}
}
I know that MutableSupplier's mutability looks super-ugly for immutability enthusiasts but I found that using it is more or less acceptable in such cases :)
What you are having is a circular dependency. The only way I can think of is to not declare the fields as final and have your dependency injected using setter injection instead of constructor injection.
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);