0

I have a JPA Entity "Users" that when I try to convert to Json via Gson I get an StackOverflowError exception

@GetMapping("/users")
public ResponseEntity getUsers() {

  List<Users> users = userRepository.findAll();
  Gson gson = new GsonBuilder().setDateFormat("dd/MMM/yyyy HH:mm:ss").create();
  String json = gson.toJson(users);

....

}

The Users entity is

@Table(uniqueConstraints={@UniqueConstraint(columnNames = {"Email"})})
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class Users {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long Id;

    @NotNull
    private String Name;

    @NotNull
    private String Email;

    @CreationTimestamp
    @Temporal(value=TemporalType.TIMESTAMP)
    private Date DateCreated;

    @Transient
    private String Password;

    @ToString.Exclude
    @JsonIgnore
    @OneToOne(mappedBy = "user", fetch = FetchType.LAZY)
    private SecUser secuser;

    @PrePersist
    protected void onCreate() {
        DateCreated = new Date();
    }

    @JsonIgnore
    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
    private final Set<Activity> activity = new HashSet<>();

}

I get the exceptions...

java.lang.StackOverflowError: null
    at java.base/sun.util.locale.provider.LocaleProviderAdapter.getAdapter(LocaleProviderAdapter.java:239) ~[na:na] java.base/java.text.DateFormatSymbols.getProviderInstance(DateFormatSymbols.java:368) ~[na:na]
    at java.base/java.text.DateFormatSymbols.getInstance(DateFormatSymbols.java:346) ~[na:na]
    at java.base/java.util.Calendar.getDisplayName(Calendar.java:2142) ~[na:na]
    at java.base/java.text.SimpleDateFormat.subFormat(SimpleDateFormat.java:1156) ~[na:na]
    at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:997) ~[na:na]
    at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:967) ~[na:na]
    at java.base/java.text.DateFormat.format(DateFormat.java:374) ~[na:na]
    at com.google.gson.internal.bind.DateTypeAdapter.write(DateTypeAdapter.java:96) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.DateTypeAdapter.write(DateTypeAdapter.java:46) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.TypeAdapters$26$1.write(TypeAdapters.java:587) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.TypeAdapters$26$1.write(TypeAdapters.java:580) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
    at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:1018) ~[gson-2.8.5.jar:na]

I've succeeded with this strategy using non-Entity objects. How can I make it work?

Andronicus
  • 25,419
  • 17
  • 47
  • 88
xain
  • 13,159
  • 17
  • 75
  • 119

2 Answers2

1

The problem lies in serializing bi-directional one-to-one and one-to-many relationship. (I'm guessing it's bidirectional, since they're mappedBy = "user").

It's because @JsonIgnore is an annotation from jackson, not from gson. To exclude field from serializing in gson, you would have to do other way - annotate evey other field with @Expose, so that fields, that are not annotated (in your case - secuser and activity) won't be serialized.

Other solution would be to make all non-serializable fields transient, but since it's an @Entity, this won't do the job. It would work, if mapped to DTO first. Despite a lot of additional annotations, the first solution seems easier.

More on exclusion in gson you can find here.

Last possible solution - use jackson instead of gson.

Andronicus
  • 25,419
  • 17
  • 47
  • 88
0

You don't set how you want the Date properties to be serialized.
Have a look here on how you can set it.

Gson gson = new GsonBuilder()
   .setDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").create();
Olivier Depriester
  • 1,615
  • 1
  • 7
  • 20