6

I want to persist all variables in a superclass only from childclass

Example:

//This class is from an API, I cannot touch or change
class SuperClass {
    private String name;
    private String info;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

@Entity
class ChildClass extends SuperClass {
    @id
    private long id;
}

I want the table to have these columns (id, name, info)

Is it doable? If yes, How?

kdureidy
  • 960
  • 9
  • 26
  • It's a private... you can just create you own name and info. http://stackoverflow.com/questions/4716040/do-subclasses-inherit-private-fields – Ya Wang Jan 28 '16 at 01:35
  • what if we have public getter/setters functions in the parent class? – kdureidy Jan 28 '16 at 02:04
  • Hibernate handles all sub and super class fields persistence automatically if you use [hibernate inheritance mapping](https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/inheritance.html). In such case, persisting sub class instance also persist all inherited fields, no matter their access modifiers. – Vlastimil Ovčáčík Jan 28 '16 at 13:23

5 Answers5

6

If the accessors are not set as final in the super class, you can override them in the child classes and add JPA annotations to the overridden accessor methods.

Example 1


class SuperClass { public String getName() { ... } public String getInfo() { ... }

@Entity
class ChildClass extends SuperClass {
  @Id
  private long id;

  public Long getId() { return id; }

  @Access(AccessType.PROPERTY)
  @Column(name = "name")
  public String getName() { return super.getName(); }

  @Access(AccessType.PROPERTY)
  @Column(name = "info")
  public String getInfo() { return super.getInfo(); }
}

Example 2


class SuperClass { public String getName() { ... } public String getInfo() { ... }

@MappedSuperClass
class NamedModel extends SuperClass {
  @Access(AccessType.PROPERTY)
  @Column(name = "name")
  public String getName() { return super.getName(); }

  @Access(AccessType.PROPERTY)
  @Column(name = "info")
  public String getInfo() { return super.getInfo(); }
}

@Entity
class ChildClass extends NamedModel {
  @Id
  private long id;
}

I have created a sample application using your code. Download the application and run the integration tests as mvn clean test and check the generated SQL to see the desired result.

manish
  • 19,695
  • 5
  • 67
  • 91
3

If you can add @MappedSuperclass annotation to your super class then you will be able to persist all those fields in super class. Since unknown annotations are ignored adding this may be possible and has no impact on existing api layer functions. The only downside to this approach is that a class used by Api is going to be marred with data layer annotation.

If you ever run into issues with mapping you may also want to use @Access(AccessType.PROPERTY)

Bunti
  • 1,730
  • 16
  • 20
2

You cannot in this example. The instance variables in the superclass are private, which means that your subclass has no access to those values. I would just create your own instance field as @YaWang suggested, and in the constructor initialize them to the value of the name and info getters in the superclass.

deepmindz
  • 598
  • 1
  • 6
  • 14
  • Thats what I did actually, I was hoping for a better solution :( – kdureidy Jan 28 '16 at 02:07
  • what would be the case if they were public or default? – kdureidy Jan 28 '16 at 02:11
  • You should look at the documentation for your persistence api. If they were default, public or protected, then it might work if you dynamically call a method to save them to the database by calling `save(super.field);` – deepmindz Jan 28 '16 at 02:51
0

For Hibernate, it can be done by defining a data mapping file in xml. Note that the mapping is using the get/set methods not the fields. Annotation is not needed. For your case, it would involve creating a ChildClass.hbm.xml with the following content.

<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="ChildClass" table="child_class">
        <id name="id" column="id" type="integer"/>
        <property name="name" column="name" type="string"/>
        <property name="info" column="info" type="string"/>
    </class>
</hibernate-mapping>

Then just load this mapping from hibernate or spring configuration depending on the application stack used. When ChildClass is persisted, it will save id, name and info to child_class table.

Dukefirehawk
  • 476
  • 1
  • 3
  • 11
0

This can be done also in JPA by using XML to override annotations in the orm.xml, without touching your "API" classes. The link happen to point to Hibernate's documentation, but applies any JPA implementation. As opposed to Hibernate's native XML files, JPA XML overrides annotations, not replaces, so you should be fine with just putting the classes from your "API" in there. Something like:

<?xml version="1.0" encoding="UTF-8"?> <entity-mappings version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"   
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd">

  <mapped-superclass class="SuperClass" />
  </mapped-superclass>
</entity-mappings>

Haven't tested above, but no specific attributes should be needed since the default behavior is to persist all.

br, Jens

Jens X Augustsson
  • 1,214
  • 12
  • 13