简体   繁体   中英

java.lang.ClassCastException while using the lambda expression and Supplier/Consumer

Hi I am trying to use Supplier and Consumer provided in Java8. I am trying to use a builder pattern where i can reuse the code every time i have to build my stanza/payload.

So I have a Stanzabuilder class where I am passing a class T (expecting any class)

public abstract class StanzaDataBuilder<T> {

     final  Supplier<T> instance;


    StanzaDataBuilder(Supplier<T> instance) {
        this.instance = instance;
    }



    public T build() {
        return this.instance.get();
    }

Now I am trying to build a stanza for one of the class (RetailProfile) For this, I wrote a builder class RetailProfileBuilder and extending StanzaBuilder and in that setting some values:

public class RetailProfileDataBuilder extends StanzaDataBuilder<RetailProfile>{

    RetailProfileDataBuilder() {
        super(RetailProfile::new);
    }

    public static RetailProfileDataBuilder of() {
        RetailProfileDataBuilder rpf= new RetailProfileDataBuilder();

        rpf.instance.get().setDomain("RetailBuffer");


        return rpf;

    }

When I debug and put system.out.println(rfb.instance.get().getDomain()) i can see the value is set , but when I am returning this rpf, value is null.

What I can see I am returning the obj <b>rpf</b> which is a new object , hence value is setting to null. So I tried returning the instance instead

return (RetailProfileDataBuilder) rpf.instance;

Here I get an exception as :

java.lang.ClassCastException: package.RetailProfileDataBuilder$$Lambda$35/457597997 cannot be cast to package.RetailProfileDataBuilder

I am calling the builder class as :

RetailProfileDataBuilder rbdb= RetailProfileDataBuilder.of().build(); 

Here i am getting the value as null for the fields i set in RetailProfileDataBuilder class.

Any idea on how i can return the rpf object with the value??

Thanks for your time

rpf.instance.get() create a new RetailProfile each time you invoke, so you will see null value instead of the value you set for previous instance

If you want to set some default value for every instance created by your Builder, you need to add some field to your builder class to maintains the state.

public class RetailProfileDataBuilder extends StanzaDataBuilder<RetailProfile>{
    String domain;
    RetailProfileDataBuilder() {
        super(RetailProfile::new);
    }

    public static RetailProfileDataBuilder of() {
        RetailProfileDataBuilder rpf= new RetailProfileDataBuilder();

        domain = "RetailBuffer"; // Here you remember the `domain` value


        return rpf;

    }

    @Override
    public RetailProfile build() {
       RetailProfile rp = super.build();
       rp.setDomain(domain); // Here you pass the builder state to your new object
       return rp;
    }
}

rpf.instance is a Supplier<RetailProfile> , not a RetailProfileDataBuilder , so you can't cast it to that type.

If you want to return the instance for which you set the domain, you can write:

public static RetailProfile of() {
    RetailProfileDataBuilder rpf= new RetailProfileDataBuilder();

    RetailProfile rp = rpf.instance.get();
    rp.setDomain("RetailBuffer");

    return rp;
}

If you want to return a RetailProfileDataBuilder that always produces a RetailProfile whose domain is set, you need to pass a different Supplier to your constructor:

RetailProfileDataBuilder() {
    super(() -> {
        RetailProfile rp = new RetailProfile(); 
        rp.setDomain("RetailBuffer"); 
        return rp;
    });
}

public static RetailProfileDataBuilder of() {
    return new RetailProfileDataBuilder();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM