I have a tiny problem using (what I assume are) generics. I have this code:
public class A{
private String name;
public String getName(){
return this.name;
}
}
public class B extends A{
private String street;
public String getStreet(){
return this.street;
}
}
public class C extends A{
private int number;
public int getNumber(){
return this.number;
}
}
And I'd like to create new classes that will look like this :
public class AChange{
private A instance;
public String doSomething(){
return A.getName();
}
}
public class BChange extends AChange{
public String street(){
return A.getStreet();
}
}
public class CChange extends AChange{
public int number(){
return A.getNumber();
}
}
And of course, A class doesn't have those methods, but the subclasses do. How can I write this code, so it will work the way I want it to?
Add a generic type parameter to AChange to be used as type of field instance:
class AChange<T extends A> {
protected T instance;
public String doSomething() {
return instance.getName();
}
}
and define it in BChange and CChange accordingly
class BChange extends AChange<B> {
public String street() {
return instance.getStreet();
}
}
class CChange extends AChange<C> {
public int number() {
return instance.getNumber();
}
}
You can do the same without generics like so
static class AChange {
private A instance;
public AChange(A instance) {
this.instance = instance;
}
public String doSomething() {
return instance.getName();
}
}
static class BChange extends AChange {
private B instance;
public BChange(B instance) {
super(instance);
this.instance = instance;
}
public String street() {
return instance.getStreet();
}
}
static class CChange extends AChange {
private C instance;
public CChange(C instance) {
super(instance);
this.instance = instance;
}
public int number() {
return instance.getNumber();
}
}
Instead of using a generic instance T, store a reference of the right type
Related
I was wondering how can I return a concrete implementation given a variable as argument in a function.
This is my test code
public interface Items {
String getName();
}
public class Car implements Items{
#Override
public String getName() {
return "Car";
}
public void drive(){
//To something
}
}
public class Shelf implements Items{
#Override
public String getName() {
return "Shelf";
}
public String getBooks(String bookName){
return bookName;
}
}
public enum Item {
CAR(Service::getCar),
TABLE(Service::getShelf),
;
Function<Service, ? extends Items> serviceFunction;
Item(Function<Service, ? extends Items> serviceFunction) {
this.serviceFunction = serviceFunction;
}
}
public class Service {
public Car getCar(){
return new Car();
}
public Shelf getShelf(){
return new Shelf();
}
public Items getItem(Item item){
return item.serviceFunction.apply(this);
}
public static void main(String[] args) {
Service service = new Service();
service.getItem(Item.CAR).getName();
// service.getItem(Item.CAR).drive(); // This is not valid.
}
}
So what I want is based on that enum I should be able to execute a set of functions related to that enum without passing the implementation identifier itself.
I know I can do this. And I will work but I was thinking of getting the concrete implementation without passing Class<T> klass.
public <T extends Items> T getItem(Item item, Class<T> klass){
return (T) item.serviceFunction.apply(this);
}
public static void main(String[] args) {
Service service = new Service();
service.getItem(Item.CAR, Car.class).drive();
}
I have the following Manager Class with the builder() method:
public class Manager extends Employee {
public static Manager.Builder builder() {
return new ManagerBuilder();
}
public abstract static class Builder<T extends Employee, B extends Builder<T,B>> extends Employee.Builder<T,B>{
}
public static class ManagerBuilder extends Builder<Manager,ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
unfortunatelly trying to build an Object with Manager.builder().age(25).build(); return a Person and not a Manager as I need.
How should I change the Manager.builder() return type to return a Manager and at the same time not clashing with the Employee.builder() Method signature.
The code Employee.builder().age(25).build(); returns Employee, which is fine.
The Employee Class is looking like this:
public class Employee extends Person {
public static Employee.Builder<Employee, EmployeeBuilder> builder() {
return new EmployeeBuilder();
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> extends Person.Builder<T,B>{
}
public static class EmployeeBuilder extends Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Person implements PersonInterface {
private Optional<Integer> age;
protected Person(Builder<?,?> builder) {
this.age = builder.age;
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> {
private Optional<Integer> age;
protected Builder() {
}
public B age(Integer age) {
if (Objects.isNull(age) || age == 0) throw new IllegalArgumentException("Age ist empty");
this.age = Optional.of(age);
return self();
}
protected abstract B self();
public abstract T build();
}
public static class PersonBuilder extends Builder<Person, PersonBuilder>{
#Override
protected PersonBuilder self() {
return this;
}
#Override
public Person build() {
return new Person(this);
}
}
}
The core problem is your strange inheritance structure which overloads the classname Builder. I cant' quite pin the problem down, but at some point your specific type information of ManagerBuilder is lost. This can be simplyfied a lot:
public class Employee extends Person {
public static EmployeeBuilder builder() {
return new EmployeeBuilder();
}
public static class EmployeeBuilder extends Person.Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Manager extends Employee {
public static ManagerBuilder builder() {
return new ManagerBuilder();
}
public static class ManagerBuilder extends Person.Builder<Manager, ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
This should solve a few of your problems.
Now you are left with one more problem. The static method builder is overloaded with incompatible return types. You find information about this at Why does Java enforce return type compatibility for overridden static methods?
If you name those methods differently, it should work.
Well your code works perfectly, and Manager.builder().age(25).build() actually returns a Manager. It is only a compile time problem.
The following Junit test should succeed (it does on my tests):
#Test
public void testEss3() throws Exception {
Person emp = Manager.builder().age(25).build();
assertTrue(emp instanceof Manager);
}
In fact, it looks like as you declare no variable to host the builder, and as the method age is not defined in Manager.Builder nor in its direct subclass Employee.Builder, the Java compiler assume that it will return an object of the class in which it is declared, that is a Person.Builder. It is not false because it is actually an ancestor class. But from that point, the compiler do not know the exact class returned by build() and only knows that it will be a Person.
But the following code is accepter by the compiler:
Manager.Builder<Manager,?> builder = Manager.builder();
Manager emp = builder.age(25).build();
public interface A extends C {
String getCh();
String getId();
String getReview();
}
public interface B extends C {
String getCh();
String getId();
String getReview();
}
#Data
#Builder
public class AImpl implements A{
private String ch;
private String id;
private String review;
}
#Data
#Builder
public class BImpl implements B{
private String ch;
private String id;
private String review;
}
so now to use the builders of these I do:
return AImpl.builder()
.ch("ch")
.id("id")
.review("somerview");
For B I do:
return BImpl.builder()
.ch("ch1")
.id("id1")
.review("some new review");
Is there a way where I can make this builder part into a function? I dont like the idea of repeating the same code again. Like where I can pass id channel and review in a function and I can the object?
Disclaimer: I have never really dealt with builders so there might be a really much better option :D
This approach writes builders for each interface individually.
This does require that the interfaces provide a setter method.
Using generics, the methods of the RootBuilder and BaseABuilder return an instance of the ImplABuilder so that the chain can continue properly.
This is a very simple implementation of the Thistype generic which in other languages exists by default. This implementation also relies on casting to the actual Thistype but if you set the generics properly, that shouldnt be an issue.
public class Test
{
public static void main(String[] args)
{
ImplA implA = ImplA
.builder()
.id("id")
.description("description")
.valueA("a")
.build();
}
}
public interface Root
{
String getId();
void setId(String id);
String getDescription();
void setDescription(String description);
}
public class RootBuilder<Thistype extends RootBuilder<Thistype, Instance>, Instance extends Root>
{
protected final Instance object;
RootBuilder(Instance object)
{
this.object = object;
}
public Thistype id(String value)
{
object.setId(value);
return (Thistype)this;
}
public Thistype description(String value)
{
object.setDescription(value);
return (Thistype)this;
}
public Instance build()
{
return object;
}
}
public interface BaseA extends Root
{
String getValueA();
void setValueA(String valueA);
}
public class BaseABuilder<Thistype extends BaseABuilder<Thistype, Instance>, Instance extends BaseA> extends RootBuilder<Thistype, Instance>
{
protected Instance object;
BaseABuilder(Instance object)
{
super(object);
}
public Thistype valueA(String value)
{
object.setValueA(value);
return (Thistype)this;
}
}
public interface BaseB extends Root
{
String getValueB();
void setValueB(String valueB);
}
public interface BaseC extends Root
{
String getValueC();
void setValueC(String valueC);
}
public final class ImplA implements BaseA
{
private String id;
private String description;
private String valueA;
private ImplA() { }
public static ImplABuilder builder()
{
return new ImplABuilder(new ImplA());
}
private static class ImplABuilder extends BaseABuilder<ImplABuilder, ImplA> // assuming ImplA is final
{
ImplABuilder(ImplA object)
{
super(object);
}
// additional methods for ImplA class
}
}
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 have a class A, with a private member int myMember. And a class B with a private member of the class A, called myA;
That is:
public class A{
private int myMember;
...
}
public class B{
private A myA;
}
I would like to be able to access:
B.myA.myMember;
but it seems I can't because myMember is private in A. The thing is, I need A to be defined as private for the purpose of the exercise (that also includes it can't be protected). Is there a way around this?
Thanks.
public class A {
private int myMember;
public int getMyMember() {
return myMember;
}
public void setMyMember(int myMember) {
this.myMember = myMember;
}
}
public class B{
private A myA;
public B() {
myA = new A();
myA.setMyMember(0);
int a = myA.getMyMember();
}
}
Use getters :
public class A {
private int myMember;
public getMyNumber() {
return myNumber;
}
}
public class B {
private A myA;
public A getA() {
return myA;
}
}
So now you can code :
B b = new B();
b.getA().getMyMember();
Since you've stated you can't create more public methods, aka getters, you could use reflection...
public class A{
private int myMember;
...
}
public class B{
private A myA;
private int get(){
try {
Field field = myA.getClass().getDeclaredField("myMember");
field.setAccessible(true);
return (int) field.get(myA);
catch (Exception e){
//Something went wrong, the field doesn't exist or a security exception
return null; //or return some "error number" like -10
}
}
}
If you can declare the private field as static then something like this is possible :
public class A {
private int myMember;
}
public class B {
public static void main (String[] args) {
int myMember = new A() {
public int getPrivate() {
return myMember;
}
}.getPrivate();
System.out.print("\n\t Id : " + myMember);
}
}