I'm using spring-data-neo4j and I have two node entities, Person and Owner extends Person
When I save person, it gets the label :Person, and when I save an owner, it gets the labels :Owner and :Person. Excellent. Exactly what I wanted.
Sometimes we have people that become owners, so I'd like to convert that person to an Owner and add the missing data (such as properties).
Obviously downcasting doesn't work. There is a way I've heard of where you can get a subclass to call its superclass with parameters. I'd like to avoid the adapter pattern as there will be hundreds of inherited fields from Person.
How do I "construct" an Owner from a Person?
/*** MAIN CLASS ***/
public class Application {
public static void main (String[] args) {
Person p = personRepository.findByEmail ("joesoap#example.com");
Owner o = new Owner(p); // Trying to construct a person from an owner
o.addProperty (...);
ownerRespository.save(o);
}
}
/*** PERSON ***/
#NodeEntity
public class Person {
public Person(Person person) {
this = person; // Obviously this won't work, but I can't think of the solution...
}
String fullName;
String email;
}
/*** OWNER ***/
#NodeEntity
public class Owner extends Person {
public Owner(Person person) {
super (person);
}
public List<Property> properties;
}
Java classes were never meant to handle cases where one wants to make an object of one type into another type. Obviously treating a subclass as its superclass, or treating a class as an object which implemented an interface, were intended, but Java just has no good way of converting an object of one class into an object of another class.
You could convert the object to XML and then read the superclass fields into the subclass; kind of a brute-force-leave-the-XML-in-memory approach.
But I think what you have is a problem where Owner should not be represented by a subclass, for the specific reason that you sometimes want to convert from one class to the other. I think your Person class should have a field of a type containing owner information, null if the person is not also an owner.
This is what you do when you need to clone an object. Unfortunately the only way is to set each property manually:
class Test {
private String prop1;
private String prop2;
public Test() {}
public Test(Test test) {
setProp1(test.getProp1());
setProp2(test.getProp2());
}
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
}
So in your case you call the cloning constructor, then setting the extra parameters in Owner
Downcasting is only allowed if there is a chance that it will succeed at runtime. In your case you would want to do as #arcy stated: add the extra parameters and initialize them as null if the person is not also an owner.
As mentioned in some other answers, creating a subclass instance from an instance of its superclass has its drawbacks, and has no direct support in Java. The resulting subclass instance is typically incomplete since it is only a clone of the superclass fields, and would then need additional field set-calls to populate subclass-specific fields. This might not be an issue in your application. Solving this through composition as suggested by #arcy is another decent option.
If you must create a subtype instance from a supertype instance, then copy-via-serialization is the best option. The key is to choose a flexible and high-performing serialization mechanism, and something better than native Java serialization. A library like Kryo is one decent option.
Using Kryo you could create a utility class to help register the serializers for the classes involved, then perform the clone-to-subclass-instance:
public class KryoDowncastCloneUtil {
private static final KryoDowncastCloneUtil instance = new KryoDowncastCloneUtil();
public static KryoDowncastCloneUtil instance() {
return instance;
}
private final Kryo kryo = new Kryo();
public <A, B extends A> void register(Class<A> superClass, Class<B> subClass) {
final Serializer<A> superClassSerializer = new FieldSerializer<>(kryo,
superClass);
// the superClass serializer is registered for both the superClass and its subClass
kryo.register(superClass, superClassSerializer);
kryo.register(subClass, superClassSerializer);
}
public <A, B extends A> B copyAndDowncast(A superClassInstance, Class<B> subClass) {
byte[] buffer = null;
try (final ByteArrayOutputStream stream = new ByteArrayOutputStream();
final Output output = new Output(stream)) {
kryo.writeObject(output, superClassInstance);
output.flush();
buffer = stream.toByteArray();
} catch (IOException e) {
// these are only from auto-close, swallow
} // auto-close stream, output
final B subClassInstanceClonedFromSuperClassInstance = kryo.readObject(new Input(
new ByteArrayInputStream(buffer)), subClass);
return subClassInstanceClonedFromSuperClassInstance;
}
}
The key here is that the same serializer, the one for the super-class A, is registered for serializing both the super-class and its sub-class B. This allows an instance of subclass B to be instantiated from the field data serialized from A - its own fields will be left null. You can then add some syntactic sugar to actual classes if desired:
public class Owner extends Person {
static {
KryoDowncastCloneUtil.instance().register(Person.class, Owner.class);
}
// ...
public static Owner fromPerson(Person person) {
return KryoDowncastCloneUtil.instance().copyAndDowncast(person, Owner.class);
}
}
Related
Java - Is it possible to extend all the subclasses of a class with a single class?
Let's explain it with an example, the actual code is quite more complex. I have an Animal class with its own class hierarchy. Let's say that it has two subclasses: Testarrosa and Viper.
public class Car {
public abstract String getManufacturer();
}
public class Testarossa extends Car{
public String getManufacturer(){
return "Ferrari";
}
}
public class Viper extends Car{
public String getManufacturer(){
return "Dodge";
}
}
I want to extend all the Car subclasses with a RegisteredCar subclass.
public class RegisteredCar extends Car {
private String plateNumber;
public RegisteredCar (String plateNumber){
this.plateNumber=plateNumber;
}
public String getPlateNumber() {
return plateNumber;
}
}
At some point, I should be able to create a new RegisteredCar of a specific subclass. Something like
RegisteredCar c = new RegisteredCar<Viper>("B-3956-AC");
And call the c.getManufacturer() to obtain "Dodge" and c.getPlateNumber() to obtain B-3956-AC. Obviously, I should still be able to create a Car c = new Viper();
That is an example. Having an attribute in Car with null value if not registered is not enough for what I need.
In short, no that is not possible. You have to unfortunately modify your object model.
For example, what about having a Registration class this way:
public interface Registration<C extends Car> {
C getCar();
String getPlateNumber();
}
This way you can extract the information relating to registration in a single class, while maintaining your Car models.
You can then do helper methods like:
Registration<Viper> registeredViper = createRegistration(new Viper(), "B-3956-AC");
As others have said, no thats not really possible and your example could be solved by changing your model
As an alternative to inheritance you could use another class to wrap a Car instance.
I would make Car an interface (though having RegisteredCar extend Car should work too) and then attempt something like the following pseudo code:
class RegisteredCar<T extends Car> implements Car {
private final T car
RegisteredCar(T car) {
this.car = car;
}
... methods for RegisteredCar
... methods from Car delegating to `this.car`
}
Please excuse the somewhat bad code, I don't have an IDE open, and I always mess up generics without an IDE to hand.
Another possible solution is to use AOP, though I don't know how in fashion that is these days as but what you are describing could be a cross cutting concern.
A final alternative might be to use a language that allows for Extensions, Traits, Protocol or some other type of 'mix in'
In java it is prohibited to extends more than 1 class.
You could build chain from classes to extends, for example.
To solve the problem of mutiple inheritance in Java → interface is used
You should avoid inheritance as much as possible. Use abstractions (interfaces) to make your code elegant and maintainable. Just google why extends is evil.
public interface Car{
String getManufacturer();
}
public interface Registerable{
boolean isRegistered();
void register(String plateNumber);
void getPlateNumber();
}
public class Viper implements Car, Registerable
{
//all methods
}
With Generic class approach as described in other answer, you will not be able to use RegisteredCar where your require to pass Car object. e.g. suppose you need to generate some invoice.
Invoice getInvoice(Car c);
In this method you cannot use RegisteredCar as it is not of Type Car. All you API which require Car are not applicable to RegisteredCar. In some cases you may need Plate Number as well as Car, There you may need to keep mapping of Plate Number and Cars. I would suggest following approach based on Decorate Pattern and delegate all Car calls to passed car object
public class RegisteredCar extends Car{
public RegisteredCar(Car c, String plateNumber){
}
#Override
String getColor(){
c.getColor();
}
}
No, it's not like C++. Multiple inheritance is not possible in Java. However you can implement multiple interfaces.
You cannot achieve that with inheritance.
Your best option is making the RegisteredCar type generic, then having a generic instance variable that holds the intended type car:
public class RegisteredCar<T extends Car> {
private String plateNumber;
private T car;
public T getCar() {
return this.car;
}
public T setCar(T car) {
this.car = car;
}
public RegisteredCar (String plateNumber){
this.plateNumber=plateNumber;
}
public String getPlateNumber() {
return plateNumber;
}
}
With this, you will be able to pass into RegisteredCar an object of any type that's a subclass of Car.
As you can notice, I have removed the extends Car part of this class, as it doesn't need to be a subclass of car itself.
Is there a reason, in the real classes, that you couldn't simply add the new feature to the existing base class?
public abstract class Car
{
public abstract String getManufacturer() ;
protected String plate_number = null ;
public String getPlateNumber()
{ return this.plate_number ; }
public boolean isRegistered()
{ return ( this.plate_number != null ) ; }
}
The question
I have a Serializable class (let's call it A) with a non-transient boolean field, and a subclass (B) for which that same field should be transient. How can I do this?
More precisely, I wish the field to be restored to the default boolean value (false) when deserializing B, though I want it to be restored to the correct value when deserializing A. The other fields inherited from A should be restored nonetheless.
Functionnally, A represents an object which is restored between sessions, and B is a particular type of A whose state should be reset on each new session.
Quick code sample:
public class A implements java.io.Serializable {
private String label;
// non-transient
private boolean field;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public boolean isField() {
return field;
}
public void setField(boolean field) {
this.field = field;
}
}
public class B extends A {
// field should be transient for this class
// label should remain non-transient
}
Some possible solutions I chose not to retain
An easy solution would be to change B extends A to A extends B, make the field transient, and add a writeObject() to A to serialize the field. However, B extends A has a functional meaning, and I am not convinced it would be wise to revert it.
I could implement a readObject() method which would overwrite the deserialized value for the field. However, this feels like a dirty solution and I do not wish to use this unless no other choice is left.
I tried to write a writeObject() method to emulate a transient field, but it does not work and I cannot tell why. If anybody has a clue, that might be my solution:
public class B extends A {
private void writeObject(ObjectOutputStream out) throws IOException {
// save current state
boolean field = isField();
// synchronized to make sure this instance is not interrogated
// while changed for serialization
synchronized (this) {
// emulate transient state and serialize
setField(false);
out.defaultWriteObject();
// restore state
setField(field);
}
}
}
Edit: #rocketboy's solution using shadowing works, but I am uncomfortable with shadowing as it will leave one unused field (A's non-transient field will never be used, while B's transient version will be written and read). It might be a solution though. Do experimented Java developers think this is a clean solution?
public class B extends A {
// shadow A's field
private transient boolean field;
#Override
public boolean getField() {
return field;
}
#Override
public void setField(boolean field) {
this.field = field;
}
}
The answer
Following #m1o2's advice, I have been able to implement my solution using the Externalizable interface:
public class B extends A implements java.io.Externalizable {
// Do not forget to have a public no-arg constructor
// for Serialization to work
public B() {
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
// Write only the fields I am interested in
out.writeObject(getLabel());
}
#Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
// Read the serialized fields IN THE ORDER THEY WERE WRITTEN
setLabel((String) in.readObject());
}
}
Please note however that this is applicable because A and B are simple classes. For classes with many fields and a tendency to evolve, this could cost more (except maybe if using some code based on reflection).
If you don't care about the Superclass fields (all of them) you can use Externalizable interface
I have the following
public abstract class MyData
{
private String sID;
public void setsID(String sID) {
this.sID= sID;
}
public String getsID() {
return sID;
}
}
This base class is being extended by 2 other classes
public class DataTypeOne extends MyData
{
private String sName;
public void setsName(String sName) {
this.sName= sName;
}
public String getsName() {
return sName;
}
}
public class DataTypeTwo extends MyData
{
private String sSummary;
public void setsSummary(String sSummary) {
this.sSummary= sSummary;
}
public String getsSummary() {
return sSummary;
}
}
I am initializing this class as follows
MyData oDataOne = new DataTypeOne();
MyData oDataTwo = new DataTypeTwo();
Reason for that is that I have a factory method which shall give me the class based on type (One or two)
With oDataOne & oDataTwo, I am able to access getsID() from the base class but not the getters & setters of the respective class.
How can I access those? I
You can't access a method that doesn't exist. All you've promised your Java compiler is that oDataOne and oDataTwo are MyData objects. Since the MyData class doesn't have the implementation-specific methods, you cannot ask Java to call those methods (since it doesn't think they exist).
If you want to access those methods, you need to either cast the object to a class that actually has the right methods, or you can add abstract method stubs to your base class, which will tell Java that those methods actually exist.
Type casting is simpler to write in the short term, but less clear, and you may run into more trouble down the road:
((DataTypeOne) oDataOne).getsName();
((DataTypeTwo) oDataOne).getsSummary(); // Throws ClassCastException!
Adding abstract stubs is more robust, but may not make sense if not all concrete subclasses should implement all abstract methods:
public abstract class MyData {
public abstract void setsName(String name);
public abstract String getsName();
public abstract void setsSummary(String summary);
public abstract String getsSummary();
}
public class DataTypeOne extends MyData {
public String getsName() {
// implement
}
public void setsName(String name) {
// implement
}
// Still have to implement these!!!
public String getsSummary() {
// raise an exception or something if appropriate
}
public void setsSummary(String summary) {
// raise an exception or something if appropriate
}
}
// Same for DataTypeTwo
Since you declared the variable as a MyData, you can only access the methods of MyData. You can get to the subclass methods by casting it to DataTypeOne or DataTypeTwo:
((DataTypeOne)oDataOne).getsName()
But you need to be sure it is of type DataTypeOne or you will get a ClassCastException
MyData oDataOne = new DataTypeOne();
this says, that your oDataOne object is of the type MyData. Even if it is created as a DataTypeOne, java can only be sure that it is defiantly a MyData instance.
If you are sure that the MyData instance is in reality also a DataTypeOne instance, you can cast and then access the DataTypeOne methods + the MyData methods.
To make sure that an object is of a specific type test:
if(oDataOne instanceOf DataTypeOne){
((DataTypeOne) oDataOne).getsName(); // this will return the Name if oDataOne is really of the type DataTypeOne
}
An object of type MyData has no knowledge of whether any other classes extends it or not, so there is no way to access members of those classes.
You will have to cast your object to the specific type to access the specific members.
If you find yourself in this situation, you can be pretty sure that your design is flawed. If you need to perform a specific action for each type of MyData extension, add a method, e.g specialAction() to the interface and hide the specifics in there. That eliminates the entire need to find out which subclass you are dealing with.
public class Base {
//long list of attributes
// no Constructor using fields
// no init methode
// i cannot change this class
}
now i extended the Base Class like:
public class subClass extends Base{
private boolean selected;
...
getter und setter
...
}
i become a list of Base object List<Base>
but i need the same list but as List<SubClass>
is there a way to initialize the Subclass from the Base Class?
example:
for(Base b: list){
SubClass sub = (SubClass)b; // Thats wrong i know
if(...){
sub.setSelected(true);
}
newList.add(sub);
}
i try to avoid the manual init of each Attribute of the Base Class to the SubClass
i update my Question as requested in the Comments:
the Design above is just an example. my QUESTIN EXACTLY IS:
why converting BaseClass into SubClass (sence Subclass extends BaseClass) is not Possible? why Java dosn't allow me to do the following:
example:
Class Base{
private String name;
.....
}
Class SubClass extends Base{
private String title;
}
then
Base b = DBController.getById(...);
SubClass sub = (SubClass)b;
after that the Object sub should have the Attribute Name from the Object b
and the title Attribute is null
why is this not the case in java?
sorry for my bad english,
thanks
If you have a List<Base>, then you cannot convert it to a List<SubClass>. This is mainly because the list may not contain instances of SubClass. The best you can do is:
List<SubClass> newList = new List<SubClass>();
for(Base b: list){
if (b instanceof SubClass) {
SubClass sub = (SubClass)b;
. . .
newList.add(sub);
}
}
Generally, however, when you find yourself doing this kind of thing, there's something wrong with your design. You might want to avoid subclassing Base and using composition instead.
EDIT Based on your comments, it sounds like you want to construct a list of SubClass instances using a list of Base instances as a start. One approach is to define a constructor for SubClass that takes a Base as an argument.
public class SubClass extends Base{
private boolean selected;
public SubClass() {
// default constructor
}
public SubClass(Base original) {
// copy constructor -- initialize some fields from
// values in original, others with default values
}
...
getter und setter
...
}
Then you can construct your new list with:
List<SubClass> newList = new List<SubClass>();
for(Base b: list){
SubClass sub = new SubClass(b);
. . .
newList.add(sub);
}
There is a way: Various Java Beans spec based manipulation.
For example:
Commons BeanUtils
for( Base base: list ){
SubClass sub = new SubClass();
PropertyUtilsBean.copyProperties( sub, base );
if(...){
sub.setSelected(true);
}
newList.add(sub);
}
This works based on get/setters of the same name. Doesn't copy internal fields.
If you needed to copy internal fields, it's actually not that hard to implement using javax.lang.reflect.
You appear to have a class with a lot of attributes and no easy way of setting them all. You have now run in to a problem where you need a class with an additional attribute but you have to deal with that mess of a base class.
I suggest that, instead of creating a subclass and casting, you create a wrapper class around the ugly one:
public class BigDumbClass {
// A lot of attributes
// No Constructor
// No init method
}
public class Wrapper {
private BigDumbClass base;
private boolean selected;
public Wrapper(BigDumbClass base) {
this.base = base;
this.selected = false;
}
//getters and setters
}
Now when you have to create that new list you can wrap everything in the old list
List<BigDumbClass> oldList = someData();
List<Wrapper> wraps = aNewList();
for (BigDumbClass bigDumb : oldList) {
Wrapper wrap = new Wrapper(bigDumb);
if (someCondition()) {
wrap.setSelected(true);
}
wraps.add(wrap);
}
Ideally, BigDumbClass would implement an interface that Wrapper could also implement, allowing the wrapper to defer all of the calls to the instance it has wrapped.
public class BigDumbClass implements SharedInterface {
// All the stuff outlined above
}
public class Wrapper implements SharedInterface {
// All the stuff outlined above
// Methods defined in SharedInterface
public void doSomething() {
base.doSomething();
}
}
Otherwise, you can provide a getter to the instance and access it directly.
BigDumbClass base = wrapper.getBase();
base.doSomething();
In Java I have two classes:
Class A
{
public String ID;
public Object Name;
}
Class B
{
public String ID;
public Object Name;
}
I want to have a method where I can pass it either a Class A or B object:
public void SomeMethod(??? arg)
{
String id = arg.ID;
Object name= arg.Name;
}
Is it possible to pass an object of either class A or B to this method? If so, how is the method's signature written?
The only solution I can think of is to create an interface that both Class A and B implements containing get and set methods to set the fields ID and Name. Then the method's signature would be a parameter whose type is the interface. I was hoping that maybe there is a simpler way, possibly with generics?
You are correct with needing to use an interface (or an abstract class) with the appropriate method signatures. To java the two class are different with nothing (beside Object) in common. You need to create a class hierarchy refelecting the commonality between them.
Use method overloading.
public void SomeMethod(A arg)
{
String id = arg.ID;
Object name= arg.Name;
}
public void SomeMethod(B arg)
{
String id = arg.ID;
Object name= arg.Name;
}
You could make an interface and have A and B implement it. It really depends on your application. For small programs, I would just stick with method overloading since it just introduces unnecessary abstraction into your program.
For larger applications where extensibility is a priority, you may want to consider using an interface. Suppose later on you want to write classes C and D which also have SomeMethod(). Using an interface makes it so that you don't have to go through your entire code and overload appropriate methods over and over again.
If you know for sure that A and B are the end of the story, then there's no need to make an interface.
EDIT: If there's a lot of code to be duplicated, then make a helper method:
public void SomeMethod(A arg)
{
HelpMePlease( arg.ID, arg.Name );
}
public void SomeMethod(B arg)
{
HelpMePlease( arg.ID, arg.Name );
}
private void HelpMePlease( String id, Object name ) {
// 1000 lines of code here
}
You don't need generic types. Simple inheritance will do the job
abstract class Base {
public String ID;
public Object Name;
}
class A extends Base {
}
class B extends Base {
}
public void SomeMethod(Base arg)
{
String id = arg.ID;
Object name= arg.Name;
}
Generics are intended to improve type safety during compilation.
What you are asking about seems to be something akin to C++ concepts or various other languages' duck typing.
In Java, if some sequence of operations need to be performed on two disparate types, you need to introduce an interface or resort to scripting/reflection.
Define two interfaces, hasID and hasName, and then:
public class MyClass<A extends hasID & hasName>{
public void SomeMethod(A object) {
String id = object.getID();
Object name= object.getName();
}
}
Where getID and getName are defined on their respctive interfaces.