1

I'm working on a Spring - Hibernate App, and I have a question about how to correctly avoid duplicate code and using Hibernate, due to the impossibility of using use multiple inheritance (I usually work with Python so this is not a "problem").

My UML:

https://i.stack.imgur.com/LdEwf.png

My class, Periodico, for example, the same for Livro or Prototexto extends GenericEntity:

@Entity
@Table(name = "periodico")
public class Periodico extends GenericEntity {

}

My question is: ¿what is the way to implement inheritance in this case of two classes?

At this moment I'm doing this and it works. But I duplicate some code (Produçao activa) in each class.

/**
 * Created by hlorenzo on 03/08/2017.
 */
@Entity
@Table(name = "prototexto")
public class Prototexto extends GenericEntity {


    private String titulo;

    /*
     Código alfanumérico composto por nº de clase + tipo (3 iniciais) + nº Id (3 cifras) + data_ano
    */
    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "numerasao")
    private String numerasao;

    /*
     La utilización del prefijo nacimiento es para que funcione con el componente fecha.component.js de forma automática.
     */
    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "publicacion_dia")
    private Integer nacimientoDia;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "publicacion_mes")
    private Integer nacimientoMes;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "publicacion_ano")
    private Integer nacimientoAno;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "primeira_linha")
    private String primeiraLinha;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "ultima_linha")
    private String ultimaLinha;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "numero_paginas")
    private Long numeroPaginas;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "descrisao")
    private String descrisao;

    @JsonView(JsonViews.DetailedList.class)
    @Column(name = "localizasao")
    private String localizasao;

    @Enumerated(value = EnumType.STRING)
    private TipoPrototexto tipo;


    private boolean revisado;

    private boolean concluido;

    @JsonView(JsonViews.DetailedList.class)
    @ManyToOne
    @JoinColumn(name="pais_id")
    private Pais pais;


    @JsonView(JsonViews.DetailedList.class)
    @ManyToOne
    @JoinColumn(name="ciudad_id")
    private Ciudad ciudad;
[...]
}

And my GenericEntity:

@MappedSuperclass
public abstract class GenericEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonView(JsonViews.List.class)
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}

Thank you so much.

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
Hugo L.M
  • 1,053
  • 17
  • 31
  • 2
    What do you mean? Java does not support multiple inheritance. – Henry Aug 14 '17 at 07:41
  • 1
    Thanks @SachinSarawgi. I Know, I just trying to reduce duplicate code. Maybe creating an interface. I think duplicate variables is not the correct way to implement that. So... if Java doesnt support multiple inheritance, should I replicate code, or I can use other ways. That's the point. Thank you again. – Hugo L.M Aug 14 '17 at 07:44
  • 1
    there is no "right" way, and that is nothing to do with the JPA API, which simply persists what you define your classes to be – Neil Stockton Aug 14 '17 at 08:04
  • 2
    Take a look at [Code Review](https://codereview.stackexchange.com/tour). This question would better fit there. –  Aug 14 '17 at 08:06
  • Ok, so I should replicate my code in each Class, because right now they extends another class (GenericEntity)? I was thinking about using interfaces. – Hugo L.M Aug 14 '17 at 08:06
  • Thanks @CodingNinja. I will – Hugo L.M Aug 14 '17 at 08:07
  • @HugoL.M No problem –  Aug 14 '17 at 08:08
  • 1
    Cross-posted [here](https://codereview.stackexchange.com/questions/172941/how-to-avoid-duplicate-code-due-to-the-impossibility-of-using-use-multiple-inher) – Vogel612 Aug 14 '17 at 08:36

1 Answers1

0

In many cases where you could use inheritance from multiple parent classes, you should instead use either interfaces (if you need to write your own implementation in the subclass, and just want to declare that you are compatible with the interfaces) or use aggregation (if you don't need to overwrite anything, just want to re-use some code, aggregation is often much more flexible).

So instead of extending GenericEntity AND Publicada, you could extend GenericEntity and aggregate Publicada.

If storing this into a database, a ORM mapper does anyway "convert" inheritance into aggregations, so its anyway much easier for your brain if you use aggregation in the first place instead of letting hibernate convert your inheritance into aggregation so that it can be stored into a database.

If you read about design pattern (there are many books about it, like "heads up design pattern" first chapter https://www.google.com/?q=head+first+design+patterns+pdf -> page 13 or google for aggregation over inheritance Inheritance vs. Aggregation or https://en.wikipedia.org/wiki/Composition_over_inheritance), you can see why aggregation has often many advantages over inheritance and why they decided to disallow inheritance from multiple classes in java.

flack
  • 111
  • 1
  • 5
  • 1
    My question is not about how to avoid duplicate code in java, but how to avoid code using Hibernate. I know I can use agregation or interfaces, but for example, if I use agregation, I need to create a new table in my DB. Like with Paises or Ciudades: `@JsonView(JsonViews.DetailedList.class) @ManyToOne @JoinColumn(name="pais_id") `private Pais pais; Thank you so much @flack. – Hugo L.M Aug 14 '17 at 08:58
  • as I wrote, inheritance with Hibernate IS indeed possible, however it has no benefit, it only hurts your brain. I don't know if you use Code-First or Database-First approach, but in case you use the Code-First approach and let hibernate generate your tables, you are able to select how hibernate should handle inheritance. And you can select two options how hibernate handles inheritance: - either it generates one big table with all 1 columns for each of the 1000 fields of all subclasses that exist and 1 additional column for the class-name - or it converts inheritance into aggregation. – flack Aug 14 '17 at 09:13
  • if you let hibernate convert inheritance into aggregation, it will generate 1 table per class, regardless if its a abstract class or not. Rows, that you put into a subclass will then get 1 row in the subclasses table and 1 row in the abstract top-level-classes table. and the subclasses table will aggregtate the toplevel classes table. So its the absolutely same like directly using aggregation your self, only if you directly use aggregation, then you have many other benefits and less headaches. – flack Aug 14 '17 at 09:19