Orika - Does not generate field-mapping; only byDefault works

2.3k views Asked by At

I have just started to use Orika and I'd like to map data from a business entity used in my application ('PaymentPlan') to a POJO that I use for data transfer ('ShopifyRecurringApplicationCharge').

Everything seems to work fine (even custom converters for String<->Date), except for the fields..

  • PaymentPlan.shopifyID (int)
  • ShopifyRecurringApplicationChargeInner.id (String)

When converting from 'ShopifyRecurr..' to 'PaymentPlan', I would expect the String to get parsed and converted to 'int', but the field value just stays '0'. The other way round, 'ShopifyRecurr...ChargeInner.ID' just stays null.

Edit: I have looked into the mapper generated by Orika and found that there is NO CODE for the attributes shopifyID/id, although I have specified them explicitly in the Orika-Mapping. I have also attached the generated source below.

Did I make any stupid mistake?

PaymentPlan

package de.dpt.persistence;

import java.io.Serializable;
import javax.persistence.*;
@Entity
@org.hibernate.annotations.Proxy(lazy=false)
@Table(name="PaymentPlan")
public class PaymentPlan implements Serializable {
public PaymentPlan() {
}


@Column(name="ID", nullable=false, length=11)   
@Id 
@GeneratedValue(generator="DE_DPT_PERSISTENCE_PAYMENTPLAN_ID_GENERATOR")    
@org.hibernate.annotations.GenericGenerator(name="DE_DPT_PERSISTENCE_PAYMENTPLAN_ID_GENERATOR", strategy="native")  
private int ID;
@Column(name="`Plan`", nullable=false, length=11)   
private int plan;

@Column(name="Activated_on", nullable=true, length=255) 
@Temporal(TemporalType.DATE)    
private java.util.Date activated_on;

@Column(name="Billing_on", nullable=true)   
@Temporal(TemporalType.DATE)    
private java.util.Date billing_on;

@Column(name="Cancelled_on", nullable=true) 
@Temporal(TemporalType.DATE)    
private java.util.Date cancelled_on;

@Column(name="Confirmation_url", nullable=true, length=255) 
private String confirmation_url;

@Column(name="Created_at", nullable=true)   
@Temporal(TemporalType.DATE)    
private java.util.Date created_at;

@Column(name="ShopifyID", nullable=false, length=11)    
private int shopifyID;

@Column(name="Name", nullable=true, length=255) 
private String name;

@Column(name="Price", nullable=false, length=255)   
private String price;

@Column(name="Return_url", nullable=true, length=255)   
private String return_url;

@Column(name="Status", nullable=true, length=255)   
private String status;

@Column(name="Terms", nullable=true, length=255)    
private String terms;

@Column(name="Test", nullable=false, length=1)  
private boolean test;

@Column(name="Trial_days", nullable=false, length=11)   
private int trial_days;

@Column(name="Trial_ends_on", nullable=true)    
@Temporal(TemporalType.DATE)    
private java.util.Date trial_ends_on;

@Column(name="Updated_at", nullable=true)   
@Temporal(TemporalType.DATE)    
private java.util.Date updated_at;

private void setID(int value) {
    this.ID = value;
}

public int getID() {
    return ID;
}

public int getORMID() {
    return getID();
}

/**
 * ET_PaymentPlan
 */
public void setPlan(int value) {
    this.plan = value;
}

/**
 * ET_PaymentPlan
 */
public int getPlan() {
    return plan;
}

public void setActivated_on(java.util.Date value) {
    this.activated_on = value;
}

public java.util.Date getActivated_on() {
    return activated_on;
}

public void setBilling_on(java.util.Date value) {
    this.billing_on = value;
}

public java.util.Date getBilling_on() {
    return billing_on;
}

public void setCancelled_on(java.util.Date value) {
    this.cancelled_on = value;
}

public java.util.Date getCancelled_on() {
    return cancelled_on;
}

public void setConfirmation_url(String value) {
    this.confirmation_url = value;
}

public String getConfirmation_url() {
    return confirmation_url;
}

public void setCreated_at(java.util.Date value) {
    this.created_at = value;
}

public java.util.Date getCreated_at() {
    return created_at;
}

public void setShopifyID(int value) {
    this.shopifyID = value;
}

public int getShopifyID() {
    return shopifyID;
}

public void setName(String value) {
    this.name = value;
}

public String getName() {
    return name;
}

public void setPrice(String value) {
    this.price = value;
}

public String getPrice() {
    return price;
}

public void setReturn_url(String value) {
    this.return_url = value;
}

public String getReturn_url() {
    return return_url;
}

public void setStatus(String value) {
    this.status = value;
}

public String getStatus() {
    return status;
}

public void setTerms(String value) {
    this.terms = value;
}

public String getTerms() {
    return terms;
}

public void setTest(boolean value) {
    this.test = value;
}

public boolean getTest() {
    return test;
}

public void setTrial_days(int value) {
    this.trial_days = value;
}

public int getTrial_days() {
    return trial_days;
}

public void setTrial_ends_on(java.util.Date value) {
    this.trial_ends_on = value;
}

public java.util.Date getTrial_ends_on() {
    return trial_ends_on;
}

public void setUpdated_at(java.util.Date value) {
    this.updated_at = value;
}

public java.util.Date getUpdated_at() {
    return updated_at;
}

public String toString() {
    return String.valueOf(getID());
}
}

ShopifyRecurringApplicationCharge

package de.shopify.api.model;

import java.util.List;

public class ShopifyRecurringApplicationCharge {

public ShopifyRecurringApplicationChargeInner
recurring_application_charge;
public List<ShopifyRecurringApplicationChargeInner>
recurring_application_charges;

public static class ShopifyRecurringApplicationChargeInner {

    public ShopifyRecurringApplicationChargeInner()  {}

    public String activated_on;
    public String billing_on;
    public String cancelled_on;
    public String capped_amount;
    public String confirmation_url;
    public String created_at;
    public String id;
    public String name;
    public String price;
    public String return_url;
    public String status;
    public String terms;
    public String test;
    public String trial_days;
    public String trial_ends_on;
    public String updated_at;

}
}

The Mapping

public enum PaymentPlanMapper {
INSTANCE;

private PaymentPlanMapper()  {
    ShopifyBaseMapper.factory.classMap(PaymentPlan.class, ShopifyRecurringApplicationChargeInner.class)
    .fieldBToA("id","shopifyID")
    .exclude("ID")
    .exclude("plan")
    .byDefault()
    .register();
}

} 

Using a filled ShopifyRecurringApplicationCharge(Inner), I use the following call to map:

PaymentPlan newPaymentPlan = mapperFacadeOrika.map(postResponse.recurring_application_charge, PaymentPlan.class);

Edit: Generated Mapper

package ma.glasnost.orika.generated;

public class Orika_ShopifyRecurringApplicationChargeInner_PaymentPlan_Mapper4020303591863$0
        extends ma.glasnost.orika.impl.GeneratedMapperBase {

    public void mapAtoB(java.lang.Object a, java.lang.Object b,
            ma.glasnost.orika.MappingContext mappingContext) {

        super.mapAtoB(a, b, mappingContext);

        de.dpt.persistence.PaymentPlan source = ((de.dpt.persistence.PaymentPlan) a);
        de.shopify.api.model.ShopifyRecurringApplicationCharge.ShopifyRecurringApplicationChargeInner destination = ((de.shopify.api.model.ShopifyRecurringApplicationCharge.ShopifyRecurringApplicationChargeInner) b);

        if ((!(((java.util.Date) source.getActivated_on()) == null))) {
            destination.activated_on = ""
                    + ((ma.glasnost.orika.Converter) usedConverters[0])
                            .convert(
                                    ((java.util.Date) source.getActivated_on()),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        } else {
            destination.activated_on = null;
        }
        if ((!(((java.util.Date) source.getBilling_on()) == null))) {
            destination.billing_on = ""
                    + ((ma.glasnost.orika.Converter) usedConverters[0])
                            .convert(
                                    ((java.util.Date) source.getBilling_on()),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        } else {
            destination.billing_on = null;
        }
        if ((!(((java.util.Date) source.getCancelled_on()) == null))) {
            destination.cancelled_on = ""
                    + ((ma.glasnost.orika.Converter) usedConverters[0])
                            .convert(
                                    ((java.util.Date) source.getCancelled_on()),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        } else {
            destination.cancelled_on = null;
        }
        if ((!(((java.lang.String) source.getConfirmation_url()) == null))) {
            destination.confirmation_url = ""
                    + ((java.lang.String) source.getConfirmation_url());
        } else {
            destination.confirmation_url = null;
        }
        if ((!(((java.util.Date) source.getCreated_at()) == null))) {
            destination.created_at = ""
                    + ((ma.glasnost.orika.Converter) usedConverters[0])
                            .convert(
                                    ((java.util.Date) source.getCreated_at()),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        } else {
            destination.created_at = null;
        }
        if ((!(((java.lang.String) source.getName()) == null))) {
            destination.name = "" + ((java.lang.String) source.getName());
        } else {
            destination.name = null;
        }
        if ((!(((java.lang.String) source.getPrice()) == null))) {
            destination.price = "" + ((java.lang.String) source.getPrice());
        } else {
            destination.price = null;
        }
        if ((!(((java.lang.String) source.getReturn_url()) == null))) {
            destination.return_url = ""
                    + ((java.lang.String) source.getReturn_url());
        } else {
            destination.return_url = null;
        }
        if ((!(((java.lang.String) source.getStatus()) == null))) {
            destination.status = "" + ((java.lang.String) source.getStatus());
        } else {
            destination.status = null;
        }
        if ((!(((java.lang.String) source.getTerms()) == null))) {
            destination.terms = "" + ((java.lang.String) source.getTerms());
        } else {
            destination.terms = null;
        }
        destination.test = ""
                + ((ma.glasnost.orika.Converter) usedConverters[0])
                        .convert(
                                java.lang.Boolean.valueOf(((boolean) source
                                        .getTest())),
                                ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        destination.trial_days = ""
                + ((ma.glasnost.orika.Converter) usedConverters[0]).convert(
                        java.lang.Integer
                                .valueOf(((int) source.getTrial_days())),
                        ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        if ((!(((java.util.Date) source.getTrial_ends_on()) == null))) {
            destination.trial_ends_on = ""
                    + ((ma.glasnost.orika.Converter) usedConverters[0])
                            .convert(
                                    ((java.util.Date) source.getTrial_ends_on()),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        } else {
            destination.trial_ends_on = null;
        }
        if ((!(((java.util.Date) source.getUpdated_at()) == null))) {
            destination.updated_at = ""
                    + ((ma.glasnost.orika.Converter) usedConverters[0])
                            .convert(
                                    ((java.util.Date) source.getUpdated_at()),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[0]));
        } else {
            destination.updated_at = null;
        }
        if (customMapper != null) {
            customMapper.mapAtoB(source, destination, mappingContext);
        }
    }

    public void mapBtoA(java.lang.Object a, java.lang.Object b,
            ma.glasnost.orika.MappingContext mappingContext) {

        super.mapBtoA(a, b, mappingContext);

        de.shopify.api.model.ShopifyRecurringApplicationCharge.ShopifyRecurringApplicationChargeInner source = ((de.shopify.api.model.ShopifyRecurringApplicationCharge.ShopifyRecurringApplicationChargeInner) a);
        de.dpt.persistence.PaymentPlan destination = ((de.dpt.persistence.PaymentPlan) b);

        if ((!(((java.lang.String) source.activated_on) == null))) {
            destination
                    .setActivated_on(((java.util.Date) ((ma.glasnost.orika.Converter) usedConverters[1])
                            .convert(
                                    ((java.lang.String) source.activated_on),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[1]))));
        } else {
            destination.setActivated_on(null);
        }
        if ((!(((java.lang.String) source.billing_on) == null))) {
            destination
                    .setBilling_on(((java.util.Date) ((ma.glasnost.orika.Converter) usedConverters[1])
                            .convert(
                                    ((java.lang.String) source.billing_on),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[1]))));
        } else {
            destination.setBilling_on(null);
        }
        if ((!(((java.lang.String) source.cancelled_on) == null))) {
            destination
                    .setCancelled_on(((java.util.Date) ((ma.glasnost.orika.Converter) usedConverters[1])
                            .convert(
                                    ((java.lang.String) source.cancelled_on),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[1]))));
        } else {
            destination.setCancelled_on(null);
        }
        if ((!(((java.lang.String) source.confirmation_url) == null))) {
            destination.setConfirmation_url(""
                    + ((java.lang.String) source.confirmation_url));
        } else {
            destination.setConfirmation_url(null);
        }
        if ((!(((java.lang.String) source.created_at) == null))) {
            destination
                    .setCreated_at(((java.util.Date) ((ma.glasnost.orika.Converter) usedConverters[1])
                            .convert(
                                    ((java.lang.String) source.created_at),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[1]))));
        } else {
            destination.setCreated_at(null);
        }
        if ((!(((java.lang.String) source.name) == null))) {
            destination.setName("" + ((java.lang.String) source.name));
        } else {
            destination.setName(null);
        }
        if ((!(((java.lang.String) source.price) == null))) {
            destination.setPrice("" + ((java.lang.String) source.price));
        } else {
            destination.setPrice(null);
        }
        if ((!(((java.lang.String) source.return_url) == null))) {
            destination.setReturn_url(""
                    + ((java.lang.String) source.return_url));
        } else {
            destination.setReturn_url(null);
        }
        if ((!(((java.lang.String) source.status) == null))) {
            destination.setStatus("" + ((java.lang.String) source.status));
        } else {
            destination.setStatus(null);
        }
        if ((!(((java.lang.String) source.terms) == null))) {
            destination.setTerms("" + ((java.lang.String) source.terms));
        } else {
            destination.setTerms(null);
        }
        if ((!(((java.lang.String) source.test) == null))) {
            destination
                    .setTest(java.lang.Boolean
                            .valueOf(
                                    ""
                                            + ((ma.glasnost.orika.Converter) usedConverters[2])
                                                    .convert(
                                                            ((java.lang.String) source.test),
                                                            ((ma.glasnost.orika.metadata.Type) usedTypes[2])))
                            .booleanValue());
        }
        if ((!(((java.lang.String) source.trial_days) == null))) {
            destination
                    .setTrial_days(java.lang.Integer
                            .valueOf(
                                    ""
                                            + ((ma.glasnost.orika.Converter) usedConverters[2])
                                                    .convert(
                                                            ((java.lang.String) source.trial_days),
                                                            ((ma.glasnost.orika.metadata.Type) usedTypes[3])))
                            .intValue());
        }
        if ((!(((java.lang.String) source.trial_ends_on) == null))) {
            destination
                    .setTrial_ends_on(((java.util.Date) ((ma.glasnost.orika.Converter) usedConverters[1])
                            .convert(
                                    ((java.lang.String) source.trial_ends_on),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[1]))));
        } else {
            destination.setTrial_ends_on(null);
        }
        if ((!(((java.lang.String) source.updated_at) == null))) {
            destination
                    .setUpdated_at(((java.util.Date) ((ma.glasnost.orika.Converter) usedConverters[1])
                            .convert(
                                    ((java.lang.String) source.updated_at),
                                    ((ma.glasnost.orika.metadata.Type) usedTypes[1]))));
        } else {
            destination.setUpdated_at(null);
        }
        if (customMapper != null) {
            customMapper.mapBtoA(source, destination, mappingContext);
        }
    }

}
1

There are 1 answers

1
mararn1618 On BEST ANSWER

I have finally realized that the problem does not lie within Orika, but my implementation of PaymentPlanMapper and the inappropriate design pattern of enum-singleton.

The result was

  • PaymentPlannerMapper was never initialized
  • My custom mapping was never registered at MapperFactory
  • Okira has automatically generated a mapper for PaymentPlan/ShopifyRecurring... on the fly when facade.map(..) was called

The automatic generation by Orika made my own mistake very hard for me to detect, because most of the things orika was doing looked good.

I have only realized what was wrong, when debugging the auto-generated mapper ('Orika_ShopifyRecurringApplicationCharge_PaymentPlan_Mapper7011935565727$0') and finding the attribute 'fromAutoMapping' being TRUE. So, for similar problems it makes sense to take a look into the generated mapper sources.

Debug generated mappers

In order to enable the sources and the debugging for the generated mappers, I have used the sections 'Enable step-debugging' and 'Generate Source and/or Class Files.' in Orika Documentation.

The documentation basically translates to calling the following code at application start:

System.setProperty(OrikaSystemProperties.COMPILER_STRATEGY,EclipseJdtCompilerStrategy.class.getName());
System.setProperty(OrikaSystemProperties.WRITE_SOURCE_FILES,"true");
System.setProperty(OrikaSystemProperties.WRITE_CLASS_FILES,"true");

Correct mapper

I have now replaced my mapper with ..

@Component
public class PaymentPlanMapper {

    private PaymentPlanMapper()  {
        ShopifyBaseMapper.factory.classMap(PaymentPlan.class, ShopifyRecurringApplicationCharge.class)
        .field("shopifyID","id")
        .byDefault()
        .register();
    }

} 

.. using Spring instead of the Enum-Singleton pattern.