#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class A{
private long id;
}
#Entity
public class B extends A{
private String bProperty;
}
#Entity
public class C extends A{
private String cProperty;
}
#Entity
public class Person{
#OneToMany
private Set<A> a;
}
when I use person.getVehicles
How can I know the A is B or C?
I'm using instanceof to check and cast it to get bProperty or cProperty.
Is there any other better way?
The only safe way is to use a polymorphic method. Even instanceof will not work because the instance might actually be a proxy, i.e. a subclass of A that is neither a B or a C, but delegates to a B or a C.
public class A{
private long id;
public abstract boolean isB();
public abstract boolean isC();
public abstract String getBProperty();
public abstract String getCProperty();
}
public class B extends A{
private String bProperty;
public boolean isB() {
return true;
}
public boolean isC() {
return false;
}
public String getBProperty() {
return bProperty;
}
public String getCProperty() {
throw new IllegalStateException("I'm not a C");
}
}
To be cleaner, try using the visitor pattern. I've written a blog post about it. It's in French, but it should be easily translatable.
Related
I have these classes:
enum Brand {
FORD, FERRARI, TESLA, RENAULT;
}
public class Car {
Brand brand;
String plate;
...
}
//getters and setters
Imagine that for some reason, I need to make Car a superclass for two new classes: CombustionCar and ElectricCar. One of the new requierements is that ElectricCar's brand attribute must be always TESLA value and not any of the other ones values.
I've thougth some solutions:
I could keep Brand attr on superclass Car, and make ElectricCar constructor to set TESLA brand. But this way could allow me to set a new Brand after creating the object
public class ElectricCar extends Car {
public ElectricCar(...){
super(Brand.TESLA, ...);
}
ElectricCar ec = new ElectricCar(...);
ec.setBrand(Brand.FORD);
I can take Brand attr out from superclass and set it on both subclasses, but setting it in ElectricCar as a class attribute with a final so anyone would be able to set a new value
public class ElectricCar extends Car {
public static final Brand brand = Brand.TESLA;
...
}
public class CombustionCar extends Car {
private Brand brand;
...
}
Avoid inheritance and use composition, but with this I wont be able to use, for example, a List which contain both:
public class ElectricCar {
private Car car;
private Brand brand = Brand.TESLA;//with no setter
...
}
public class CombustionCar {
private Car car;
private Brand brand;
...
}
I'm asking for the most elegant and manteinable solution, I think any of them would be nice to resolve my problem.
Your first solution is incorrect given that you required a non editable BRAND for an electric car.
Your second solution just doesn't work at all excepted if you override both getter and setter of brand field to use your static field, which is not "elegant and mantainable"
Your third solution doesn't make use of object oriented concept.
A simple solution I would use is to let the field brand and its getter in Car superclass, but I'd only define the setter in the CombustionCar class.
Alternatively, if you extend your model, you could create an intermediate abstract superclass "FreeBrandCar" which implements the setter.
Solution with the setter in CombustionCar
abstract public class Car {
protected String brand;
protected Car(final String b) {
this.brand = b;
}
public String getBrand() {
return this.brand;
}
}
public class ElectricCar extends Car {
public ElectricCar() {
super("Tesla");
}
}
public class CombustionCar extends Car {
public CombustionCar(final String b) {
super(b);
}
public void setBrand(final String b) {
this.brand = b;
}
}
Solution with an intermediate class
abstract public class Car {
protected String brand;
protected Car(final String b) {
this.brand = b;
}
public String getBrand() {
return this.brand;
}
}
abstract public class FreeBrandCar extends Car {
public FreeBrandCar (final String b) {
super(b);
}
public void setBrand(final String b) {
this.brand = b;
}
}
public class ElectricCar extends Car {
public ElectricCar() {
super("Tesla");
}
}
public class CombustionCar extends FreeBrandCar {
public CombustionCar(final String b) {
super(b);
}
}
It respects your requirements :
public void test() {
ElectricCar ec = new ElectricCar();
ec.setBrand("..."): // Doesn't compile
CombustionCar cc = new CombustionCar("Ford"); // OK
cc.setBrand("Fiat"); // OK
Arrays.asList(ec, cc)
.stream()
.forEach(car -> System.out.println(car.getBrand())); // prints Tesla and Fiat
}
I am having two java class as below,
public class Class1{
private Object actionObject;
public Object getActionObject() {
return actionObject;
}
public void setActionObject(Object actionObject) {
this.actionObject = actionObject;
}
}
Second class
public class Class2 {
private Long id;
private int idver;
private int valueDate;
}
There are two statement as below,
Class1 deserializedValue = (Class1) event.getDeserializedValue();
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
I want to mock the second statement
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
how can i do this?
For testing purposes you can use a strategy pattern. You just need an interface or an abstract class with two different implementations. One of them is the mock implementation, something like this:
public interface EventStrategy {
// More methods...
boolean isAssignableFrom(final Object object);
}
public class MyEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return Class2.class.isAssignableFrom(object.getClass());
}
}
public class MockEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return true;
}
}
I have the following class structure:
public abstract class Creature{
private String name;
//strategy pattern composition
private SkillInterface skill;
}
public interface SkillInterface {
void attack();
}
public class NoSkill implements SkillInterface {
#Override
public void attack() {
//statements
}
}
My goal is to persist Creature objects at one table in database. Subclasses of SkillInterface are without any fields. As they determine the behaviour, I want to convert selected SkillInterface class name to a String, as I only need to persist the classname of the current skill strategy of creature, with a String like skill.getClass().getSimpleName(). I tried to implement it with #Converter annotation, using AttributeConverter class to convert SkillInterface to String and save, but always had mapping exceptions. I want to be able to save it as String and retrieve as SkillInterface object.
But how can I implement it with Hibernate? Or do I have a design mistake?
Ok looks like I have found a basic solution that can be used to persist Strategy Pattern interfaces implementations. I used a #Converter annotation and a AttributeConverter class to convert strategy class names to column while saving to database and cast the retrieved String back to strategy class as following:
#Entity
public class Creature {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Convert(converter = SkillConverter.class)
private SkillInterface skill;
}
public class SkillConverter implements AttributeConverter<SkillInterface,String> {
#Override
public String convertToDatabaseColumn(SkillInterface skill) {
return skill.getClass().getSimpleName().toLowerCase();
}
#Override
public SkillInterface convertToEntityAttribute(String dbData) {
//works as a factory
if (dbData.equals("noskill")) {
return new NoSkill();
} else if (dbData.equals("axe")) {
return new Axe();
}
return null;
}
}
public interface SkillInterface {
public String getSkill();
void attack();
}
public class NoSkill implements SkillInterface{
public String getSkill() {
return getClass().getSimpleName();
}
#Override
public void attack() {
//strategy statements
}
}
You can use a proxy field to this for you like below:
abstract class Creature {
#Column
private String name;
// strategy pattern composition
private SkillInterface skill;
#Column
private String skillName;
public String getSkillName() {
return skill.getClass().getSimpleName();
}
public void setSkillName(String skillName) {
//ignore
}
}
I am currently making a service in which there are lots of public API's. And the response and request objects overlap a lot. So, I was thinking that is there a way by which we can generalise the pojo creation for the request/response objects.
Sometimes the response object is identical to the request object with one or two extra fields.
Let me give you an example.
#Data
public class Request {
private A objA;
private B objB;
}
#Data
public class Response {
private A objA;
private B objB;
private C objC;
}
#Data
public class A {
private D objD;
}
#Data
public class B {
private String sB;
private E obje;
}
#Data
public class C {
private String sC;
}
Similary, D and E are pojos as well. The thing is that there is a lot of similarity(overlapping fields) in request/response objects.
Your solution is probably inheritance: Create a parent abstract object type with the overlapping fields and have the request and response objects extend it and specify any extra (unique) fields they need.
Inheritence
public abstract class Common {
private String overlapfield1;
private String overlapfield2
}
public class Request extends Common {
private String requestField1;
private String requestField2;
}
public class Response extends Common {
private String responseField1;
private String responseField2;
}
You could also approach this using composition: Create an object type with the overlapping fields and include this object as a sub-object of the Request/Response types:
Composition
public class Common {
private String overlapfield1;
private String overlapfield2
}
public class Request {
private String requestField1;
private String requestField2;
private Common common;
}
public class Response {
private String responseField1;
private String responseField2;
private Common common;
}
There are pros and cons to each approach which are widely discussed on this and other boards. These however, are the two standard approaches to dealing with such a problem.
It really depends on what you are trying to achieve. I don't see it being a huge problem repeating the fields but you've given an abstract use case rather than a real world situation where I can understand what you're trying to achieve.
Perhaps you want to pass your #Data objects to the same services? In which case you might want to use interfaces because a class can implement multiple interfaces.
Eg
public interface AContiner {
A getA();
void setA(A a);
}
public interface BContiner {
B getB();
void setB(B b);
}
#Data
public class Bean1 implements AContainer {
private A a;
}
#Data
public class Bean2 implements AContainer, BContainer {
private A a;
private B b;
}
public class MyFantasticService {
public void doStuffWithA(AContainer data) {
System.out.println(data.getA());
}
public void doStuffWithB(BContainer data) {
System.out.println(data.getB());
}
}
I was trying to use lombok for my project.
I have a class A:
#Data
#Builder
public class A {
Integer a1;
}
and a class B:
#Data
public class B extends A {
Integer b1;
#Builder
public B(Integer b1, Integer a1) {
super(a1);
this.b1 = b1;
}
}
I am getting an error saying builder() in B cannot override builder() in A, as return type in BBuilder is not compatible with return type in ABuilder.
Is there some way to do this using lombok?
I do not want to write the complete builder for for B, unless I don't have any other option.
PS: I have given explicit constructor for class B due to Issue.
I tried searching, but I could not find a good solution for the same.
Here we just need to call super of the builder.
#Data
public class B extends A {
Integer b1;
#Builder
public B(Integer b1, Integer a1) {
super(a1);
this.b1 = b1;
}
public static class BBuilder extends ABuilder{
BBuilder() {
super();
}
}
}
If you are using Lombok 1.18.4 along with IntelliJ, following code shall work for you:
#Data
#Builder
class A {
Integer a1;
}
#Data
class B extends A {
Integer b1;
#Builder (builderMethodName = "BBuilder")
public B(Integer b1, Integer a1) {
super(a1);
this.b1 = b1;
}
}
public class Main {
public static void main(String[] args){
System.out.println(B.BBuilder().a1(1).b1(1).build());
}
}
One a side note, #SuperBuilder annotation didn't work in IntelliJ at time of writing this answer. If you have multiple level of inheritance, please avoid Lombok or it will make your Java models messy.
Lombok has introduced experimental features with version: 1.18.2 for inheritance issues faced with Builder annotation, and can be resolved with #SuperBuilder annotation
Please use lombok version: 1.18.2, #SuperBuilder annotations in child/parent class
Both child and parent should be marked with #SuperBuilder.
Having both parent and child as #Builder won't work.
Parent class A:
#Data
#SuperBuilder
public class A {
Integer a1;
}
Child class B:
#Data
#SuperBuilder
public class B extends A {
Integer b1;
}
After hours of hacking at this, I found a viable solution without using the #SuperBuilder. Consider an example -
public class A{
int x;
#Builder(toBuilder = true)
public A(int x){
this.x = x;
}
public static class ABuilder{
protected ABuilder(){} //Note this is important, otherwise BBuilder won't be able to access private no-args constructor of ABuilder
}
}
public class B extends A{
#Builder(builderMethodName="BBuilder", toBuilder=true)
public B(int x){
super(x);
}
public static class BBuilder extends ABuilder{
BBuilder(){
super();
}
}
}
public static void main(){
B obj = new B();
//we can use the existing obj as obj.toBuilder().x(5).build();
//this will return an object of B and not A
}
P.S : I am not sure if #SuperBuilder is an experimental feature still ; so didn't want to take chances