-1
\$\begingroup\$

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:

http://i.imgur.com/9GD1sjV.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.

/**
 * 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;
[...]
}

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;
    }

}

The problem is that my classes extends GenericEntity and now I don't know how to implement the second relationship and use hibernate. Maybe using interfaces? or should I implement another way.

\$\endgroup\$
1
\$\begingroup\$

I've had a lot of occasions to face similar problems, but must admit that there is no ideal solution. It is difficult to avoid code duplications in JPA entities definitions.

However, there are some things that I can recommend.

Both Fasterxml and JPA annotations work on fields and on methods, which makes possible to extract common things to interfaces.

For example, you have several entities that contain titulo and descricao fields like the one of your example.

You can create interfaces to manage JSON representations of these fields, for example:

public interface Intitulado {

  @JsonView(JsonViews.List.class)
  @JsonProperty("titulo")
  String getTitulo();

}

By analogy, there can be Descrito interface.

I also recommend to always specify @JsonProperty annotation: if the name of the field changes some day, the JSON API will not be broken.

If Lombok is used in the project, this approach allows to reduce dozens of lines of code.

Now, the initial class will resemble the following:

@Data
public class Prototexto implements Intitulado, Descrito {

  private String titulo;

  private String descricao;

}

But if you need to change the JSON view for this object only, you'll have to override the getter, which brings back the verbosity.

Similar approach can be used for JPA annotations if the relationship between entities is not very complex, but there are many pitfalls with them anyway and duplications will not be avoidable in many cases.

Other remarks:

1) Why do you use nacimientoDia, nacimientoMes and nacimientoAno fields instead of a single nacimiento field typed as LocalDate?

2) Long might be too much for numeroPaginas field. Integer is hugely enough.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your time @Antot. 1) Because it is an article cataloger, where you can know the year, but not the month. Or the month and year, but not the day. 2) Certain collections of hundreds of thousands of books can result in many pages. Probably got there by the existing limit anyway. But all the cases of groupings are unknown, I must opt for the highest ranking. \$\endgroup\$ – Hugo L.M Sep 23 '17 at 11:16
  • \$\begingroup\$ I finally opted to use the legacy in Java and leave the database as it was. As soon as I finish it, I'll put the code in my github. \$\endgroup\$ – Hugo L.M Sep 23 '17 at 11:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.