Two Enums implementing the same interface sharing a method - java

I have two Enums implementing the same interface
public interface MetaEnum{
String getDefaultValue();
String getKey();
}
public enum A implements MetaEnum{
ONE("1"), TWO("2");
private String val;
A(final v){
val = v;
}
#Override
public String getDefaultValue() {
return value;
}
#Override
public String getKey() {
return (this.getClass().getPackage().getName() + "." + this.getClass().getSimpleName() + "." +
this.toString()).toLowerCase();
}
}
public enum B implements MetaEnum{
UN("1"), DEUX("2");
private String val;
B(final v){
val = v;
}
#Override
public String getDefaultValue() {
return value;
}
#Override
public String getKey() {
return (this.getClass().getPackage().getName() + "." + this.getClass().getSimpleName() + "." +
this.toString()).toLowerCase();
}
...other methods specific to this enum
}
I have duplicated code and I would like to avoid it. Is there a way to implement getKey in a sort of abstract class? I looked at this question Java Enum as generic type in Enum but it cannot adapt it to what I need.

The default method from Java 8 should help you :)
This feature allows you to implement method inside an interface.
public interface MetaEnum {
String getValue();
default String getKey() {
return (this.getClass().getPackage().getName() + "." +
this.getClass().getSimpleName() + "." +
this.toString()).toLowerCase();
}
}
Unfortunately, you can't implement a default method for getters, so you still have some duplicate code.

Extract the common code to the separate class:
class MetaEnumHelper {
private String val;
MetaEnumImpl(final v){
val = v;
}
public String getDefaultValue() {
return value;
}
public String getKey(MetaEnum metaEnum) {
return (metaEnum.getClass().getPackage().getName() + "." + metaEnum.getClass().getSimpleName() + "." +
metaEnum.toString()).toLowerCase();
}
}
public enum A implements MetaEnum{
ONE("1"), TWO("2");
private MetaEnumHelper helper;
A(final v){
helper = new MetaEnumHelper(v);
}
#Override
public String getDefaultValue() {
return helper.getDefaultValue();
}
#Override
public String getKey() {
return helper.getKey(this);
}
}
public enum B implements MetaEnum{
UN("1"), DEUX("2");
private MetaEnumHelper helper;
B(final v){
helper = new MetaEnumHelper(v);
}
#Override
public String getDefaultValue() {
return helper.getDefaultValue();
}
#Override
public String getKey() {
return helper.getKey(this);
}
...other methods specific to this enum
}

Related

Java Step Builder with Conditional Steps

I'm busy implementing Step Builders into a Java application and I've written some horrendous code. I'm quite certain I'm missing a necessary step.
For an example, I'll use the buildable class Machine.java
public class Machine {
private String type;;
private boolean mobile;
private final String mobileType;
public Machine(MachineBuilder builder) {
this.type = builder.type;
this.mobile = builder.mobile;
this.mobileType = builder.mobileType;
}
public String getType() { return this.type; }
public boolean getMobile() { return this.mobile; }
public String getMobileType() { return this.mobileType; }
}
And the step builder for it as MachineBuilder.java
public class MachineBuilder {
public String type;
public boolean mobile;
public String mobileType;
public MachineBuilder() { }
// initialize builder
public Builder start() {
return new Builder();
}
// interfaces
public interface iType {
iBuild withType(String type);
}
public interface iMobileType {
iBuild withMobileType(String mobileType);
}
public interface iBuild {
iMobileType withMobile();
iBuild withMobileType(String mobileType);
Machine build();
}
// subclass to return
public static class Builder extends MachineBuilder implements iType, iMobileType, iBuild {
public iBuild withType(String type) {
super.type = type; return this;
}
public iMobileType withMobile() {
super.mobile = true; return this;
}
public iBuild withMobileType(String mobileType) {
super.mobileType = mobileType; return this;
}
public Machine build() {
return new Machine(this);
}
}
}
The intention is to have type as a required step, then mobile as optional but if mobile is used then mobileType must be used as well.
It's only half working though
// fine
Machine car = new MachineBuilder()
.start().withType("car").withMobile().withMobileType("driving").build();
System.out.println(car.getType() + ":" + car.getMobile() + ":" + car.getMobileType());
// fine
Machine washingMachine = new MachineBuilder()
.start().withType("washingMachine").build();
System.out.println(washingMachine.getType() + ":" + washingMachine.getMobile() + ":" + washingMachine.getMobileType());
// corrupt (no type)
Machine boat = new MachineBuilder()
.start().withMobile().withMobileType("sailing").build();
System.out.println(boat.getType() + ":" + boat.getMobile() + ":" + boat.getMobileType());
// corrupt (no anything)
Machine bicycle = new MachineBuilder()
.start().build();
System.out.println(bicycle.getType() + ":" + bicycle.getMobile() + ":" + bicycle.getMobileType());
I had to initialize the builder object with the method start but this is not implementing any of the interfaces so just calling start then build will corrupt the object. Similarly calling the optional method for mobile allows it to bypass the type.
Is it possible to force flow direction from the start without using a start method at all? I feel like I am missing something very stupid.
PS. sorry for slapping so much code into the question I just wanted to illustrate the issue as best as I can
Thrill to answer this question. I try to rewrite your code. Just reorganize it following Step Builder Pattern's strategy.
Add no description here, hope you can easily understand the code.
class Machine {
private String type;
private boolean isMobile;
private String mobileType;
public static TypeStep builder(){
return new MachineBuilder();
}
public interface TypeStep{
IsMobileStep withType(String type);
}
public interface IsMobileStep{
MobileTypeStep withMobile(boolean isMobile);
}
public interface MobileTypeStep{
Build withMobileType(String mobileType);
}
public interface Build{
Machine build();
}
public static class MachineBuilder implements TypeStep, IsMobileStep, MobileTypeStep, Build {
private String type;
private boolean isMobile;
private String mobileType;
#Override
public IsMobileStep withType(String type) {
this.type = type;
return this;
}
#Override
public MobileTypeStep withMobile(boolean isMobile) {
this.isMobile = isMobile;
return this;
}
#Override
public Build withMobileType(String mobileType) {
this.mobileType = mobileType;
return this;
}
#Override
public Machine build() {
return new Machine(this);
}
}
private Machine(MachineBuilder machineBuilder) {
this.type = machineBuilder.type;
this.isMobile = machineBuilder.isMobile;
this.mobileType = machineBuilder.mobileType;
}
public String getType() {
return type;
}
public boolean isMobile() {
return isMobile;
}
public String getMobileType() {
return mobileType;
}
}
Test run:
public class Main{
public static void main(String[] args) {
Machine car = Machine.builder().withType("car").withMobile(true).withMobileType("driving").build();
System.out.println("Model 1:"+ car.getType() +":"+ car.isMobile()+":"+car.getMobileType());
Machine boat = Machine.builder().withType("boat").withMobile(true).withMobileType("driving").build();
System.out.println("Model 2:"+ boat.getType() +":"+ boat.isMobile()+":"+boat.getMobileType());
}
}
Output:
Model 1:car:true:driving
Model 2:boat:true:driving
For better readability: Github Repo Step Builder
I think your builder implementation is very difficult and not very correct.
The typical builder should have private constructors, initial methods, field setters and build methods. I would do so:
public class MachineBuilder {
public String type;
public boolean mobile;
public String mobileType;
private MachineBuilder (final String type, final boolean mobile, final String mobileType) {
this.type = type;
this.mobile = mobile;
this.mobileType = mobileType;
}
private MachineBuilder(){
}
public MachineBuilder setType(final String source) {
this.type = source;
return this;
}
public MachineBuilder setMobile(final boolean source) {
this.mobile = source;
return this;
}
public MachineBuilder setMobileType(final String source) {
this.mobileType = source;
return this;
}
public static MachineBuilder init() {
return new MachineBuilder();
}
public static MachineBuilder init(final String type, final boolean mobile, final String mobileType) {
return new MachineBuilder(type, mobile, mobileType);
}
public MachineBuilder build() {
return Machine(this.type, this.mobile, this.mobileType);
}
}

Can we have space within a constant in Enum in Java

I need something like this
public enum SolutionType {
RMS,
CPA,
BUSINESS DRIVERS,
NA
}
where BUSINESS DRIVERS is a value with space
Java forbids the use of spaces in enums.
However you could use an underscore and implement a custom toString():
public enum SolutionType {
RMS, CPA, BUSINESS_DRIVERS, NA;
#Override
public String toString() {
return this.name().replace("_", " ");
}
}
Or just add a custom field to the enum:
public enum SolutionType {
RMS, CPA, BUSINESS_DRIVERS("BUSINESS DRIVERS"), NA;
private String readableName;
private SolutionType() {
this.readableName = this.name();
}
private SolutionType(String name) {
this.readableName = name;
}
public String getReadableName() {
return this.readableName;
}
}
or a mix of the two...
public enum SolutionType {
RMS, CPA, BUSINESS_DRIVERS("BUSINESS DRIVERS"), NA;
private String readableName;
private SolutionType() {
this.readableName = this.name();
}
private SolutionType(String name) {
this.readableName = name;
}
#Override
public String toString() {
return this.readableName;
}
}

Java builder pattern with non-trivial subclass tree

I'm familiar with using the builder pattern with generics and subclassing, but I can't see how to make it work with a non-trivial tree of subclasses (i.e. C extends B extends A). Here's a simple example of what I'm trying to do:
class A {
private final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() { return value; }
public static class ABuilder<T extends ABuilder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T) this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static BBuilder builder() {
return new BBuilder();
}
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() { return name; }
public static class BBuilder<U extends BBuilder<U>> extends ABuilder<BBuilder<U>> {
private String name;
public U withName(String name) {
this.name = name;
return (U) this;
}
public B build() {
return new B(this);
}
}
}
Everything is fine if I declare BBuilder without the generic type:
public static class BBuilder extends ABuilder<BBuilder>
Since I want BBuilder to be extended by a CBuilder, I'm trying to use the same sort of Curiously Recurring Template Pattern as ABuilder. But like this, the compiler sees BBuilder.withValue() as returning an ABuilder, not a BBuilder as I want. This:
B b = builder.withValue(1)
.withName("X")
.build();
doesn't compile. Can anyone see what I'm doing wrong here, I've been going round trying different patterns of generics but can't get it to work.
Thanks to anyone who has any advice.
It seems that your mistake only with declaring correct parameter:
class A {
private final int value;
public static <T extends Builder<T>> T builderA() {
return (T)new Builder<>();
}
protected A(Builder<? extends Builder<?>> builder) {
value = builder.value;
}
public static class Builder<T extends Builder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T)this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static <T extends Builder<T>> T builderB() {
return (T)new Builder<>();
}
protected B(Builder<? extends Builder<?>> builder) {
super(builder);
name = builder.name;
}
public static class Builder<T extends Builder<T>> extends A.Builder<T> {
private String name;
public Builder<T> withName(String name) {
this.name = name;
return this;
}
public B build() {
return new B(this);
}
}
}
Client code:
A a = A.builder().withValue(1).build();
B b = B.builder().withValue(2).withName("xx").build();
Are you certain you need generics? This hierarchy seems to work fine without generics.
static class A {
protected final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return "A{" +
"value=" + value +
'}';
}
public static ABuilder builder() {
return new ABuilder();
}
public static class ABuilder {
protected int value;
public ABuilder withValue(int value) {
this.value = value;
return this;
}
public A build() {
return new A(this);
}
}
}
static class B extends A {
protected final String name;
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "B{" +
"value=" + value +
", name='" + name + '\'' +
'}';
}
public static BBuilder builder() {
return new BBuilder();
}
public static class BBuilder extends ABuilder {
private String name;
public BBuilder withName(String name) {
this.name = name;
return this;
}
#Override
public BBuilder withValue(int value) {
this.value = value * 2;
return this;
}
public B build() {
return new B(this);
}
}
}
static class C extends B {
private final String otherName;
protected C(CBuilder builder) {
super(builder);
this.otherName = builder.otherName;
}
public String getName() {
return otherName;
}
#Override
public String toString() {
return "C{" +
"value=" + value +
", name='" + name + '\'' +
", otherName='" + otherName + '\'' +
'}';
}
public static CBuilder builder() {
return new CBuilder();
}
public static class CBuilder extends BBuilder {
private String otherName;
public CBuilder withName(String name) {
this.otherName = name;
return this;
}
public C build() {
return new C(this);
}
}
}
public void test() {
A a = A.builder().withValue(10).build();
B b = B.builder().withValue(10).withName("B").build();
C c = C.builder().withName("C").build();
System.out.println("a = "+a);
System.out.println("b = "+b);
System.out.println("c = "+c);
}

toString() method is not inherting from its super class

I'm working on a task which has the following classes:
Vehicle.java ( Abstract Class)
NewVehicle.java subClass of Vehicle.java
UsedVehicle.java subClass of Vehicle.java
VehicleParser.java used as a parser
Drive Class which is used as main
In the VehicleParser class I determine which object it is. Either it is a NewVehicle object or a UsedVehicle. And in the Drive class I fill an ArrayList with the Vehicle objects.
Now When I'm trying to System.out.println an Arraylist the drive class is just invoking toString method declared in UsedVehicle/NewVehicle but not invoking the method declared in the Vehicle.java class. I need it to first invoke the method toString of Vehicle and then concat the toString of UsedVehicle/NewVehicle with it.
Here is the Code:
Vehicle
public abstract class Vehicle {
protected String make;
protected int modelYear;
protected String motivePower;
protected double licenseFee;
public Vehicle(String make,int modeYear,String motivePower) {
this.make = make;
this.modelYear= modeYear;
this.motivePower = motivePower;
this.licenseFee = 0.0;
}
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public int getModelYear() {
return modelYear;
}
public void setModelYear(int modelYear) {
this.modelYear = modelYear;
}
public String getMotivePower() {
return motivePower;
}
public void setMotivePower(String motivePower) {
this.motivePower = motivePower;
}
public double getLicenseFee() {
return licenseFee;
}
public void setLicenseFee(double licenseFee) {
this.licenseFee = licenseFee;
}
public abstract void computeLicenseFee();
public String toString()
{
return "\nMake:\t\t"+getMake()+
"\nModel Year:\t"+getModelYear()+
"\n Motive Power:\t"+getMotivePower()+
"\nLicense Fee:\t"+getLicenseFee();
}
public static class UsedVehicle extends Vehicle
{
public String previousLicenseState;
public int currentYear;
int yearsOld = 0;
public UsedVehicle(String make, int modelYear, String power, String previousState, int currentYear)
{
super(make,modelYear,power);
this.previousLicenseState = previousState;
this.currentYear = currentYear;
}
public String getPreviousLicenseState() {
return previousLicenseState;
}
public void setPreviousLicenseState(String previousLicenseState) {
this.previousLicenseState = previousLicenseState;
}
public int getCurrentYear() {
return currentYear;
}
public void setCurrentYear(int currentYear) {
this.currentYear = currentYear;
}
public void computeLicenseFee() {
double baseFee = 100.00;
double titleTransferFee = 15.00;
double smogWaiverFee = 0.00;
double smogAbatement = 0.00;
yearsOld = getCurrentYear() - getModelYear();
if(yearsOld > 5)
{
smogWaiverFee = 8.00;
}
if("gas".equalsIgnoreCase(getMotivePower()))
{
smogAbatement = 20.00;
}
licenseFee = baseFee + smogAbatement + titleTransferFee + smogWaiverFee;
}
public String toString()
{
return "\n Years Old:\t"+yearsOld+
"\n Previous State:\t"+getPreviousLicenseState();
}
}
public static class NewVehicle extends Vehicle
{
public double vehiclePrice;
public NewVehicle(String make, int modeYear, String motivePower,double price) {
super(make, modeYear, motivePower);
this.vehiclePrice = price;
}
public double getVehiclePrice() {
return vehiclePrice;
}
public void setVehiclePrice(double vehiclePrice) {
this.vehiclePrice = vehiclePrice;
}
public void computeLicenseFee() {
double baseFee = 150.00;
double smogAbatement = 0.00;
double priceFee = 0.00;
if("gas".equalsIgnoreCase(getMotivePower()))
{
smogAbatement = 20.0;
priceFee = getVehiclePrice()*0.15;
}
licenseFee = baseFee + smogAbatement + priceFee;
}
public String toString()
{
return "Price:\t\t$"+getVehiclePrice();
}
}
}
Parser
public class VehicleParser {
public static Vehicle parseStringToVehicle(String lineToParse)
{
Vehicle vehicleObj = null;
Vehicle.UsedVehicle usedVeh = new Vehicle.UsedVehicle(make, modelYear, power, previousState, currentYear);
return vehicleObj;
}
}
DriveClass
Vehicle obj = VehicleParser.parseStringToVehicle(inputInfo);
vehicleList.add(obj);
System.out.println(vehicleList.get(i));
You are overriding the toString() method. Java doesn't do any special magic here. If you want the super class' method to be called, you need to do so explicitly with the super keyword:
#Override
public String toString()
{
return super.toString() + // Here
"\n Years Old:\t"+yearsOld+
"\n Previous State:\t"+getPreviousLicenseState();
}
Just consider this example:
public class A {
public String someMethod() {
return "A method";
}
}
public class B extends A {
#Override
public String someMethod() {
return "B method";
}
}
public class C extends B {
#Override
public String someMethod() {
return "C method";
}
}
Basically what's going on here is that when you inherit the parent class, you're overriding everything that's in parent class's method and you're giving new definition to it. By Overriding parent class's method, you're saying that:
I'm giving a new fresh definition to this method. From now onward, for all of my objects and my child's object, this is only going to be the definition that would be considered and any of parent's method definition is void.
Now if you want the parent's method definition to be called before calling this method definition, then you'd have to specifically state that using super.methodName() in your code.
public class A {
public String someMethod() {
return "A method";
}
}
public class B extends A {
#Override
public String someMethod() {
return super.someMethod() + "B method";
}
}
public class C extends B {
#Override
public String someMethod() {
return super.someMethod() + "C method";
}
}
When you call the subclass methods the overridden methods will be called and all the definitions in the parent's method will be overridden and you will get only the overridden method definition. So inprder to use the parents' method definition as well you need to use the super() method in your child class method...
return super.toString() + " is a new car!";

Guice Multibinder for Annotations with Specific Value

I know that I can do a Guice multibind with a specific annotation as follows
Multibinder.newSetBinder(binder(), Bound.class, Annotation.class);
But can I do a more specific multibind on classes that are not only annotated with Annotation.class but also have a specific value, e.g. #Annotation("type1")?
In this case you could implement your annotation and pass an instance of it to the Multibinder static factory method:
static class YourAnnotationImpl implements YourAnnotation {
private final String value;
YourAnnotationImpl(String value) {
this.value = value;
}
#Override public String value() {
return value;
}
#Override public Class<? extends Annotation> annotationType() {
return YourAnnotation.class;
}
#Override public String toString() {
return "#" + YourAnnotation.class.getName() + "(value=" + value + ")";
}
#Override public boolean equals(Object o) {
return o instanceof YourAnnotationImpl
&& ((YourAnnotationImpl) o).value().equals(value());
}
#Override public int hashCode() {
return (127 * "value".hashCode()) ^ value.hashCode();
}
}
...
Multibinder.newSetBinder(binder(), Bound.class, new YourAnnotationImpl("type1");

Categories