I was trying to turn all my DB into Lazy loading, because it got too big (Like millions), in order to not load everything i applied a lazy, and started doing Spring Projections, then, in the projection, when i add one Entity, it shows the Entity correctly in postman, but when another entity is added, both are the same, but one has some other eager loadings, the one with the eagers throws an error and the other doesn't.
I think is because the other eager tables
@JsonIgnoreProperties("decoratedClass")
public interface UbicacionesLugaresProjection {
Integer getId();
int getTipolugar();
Lugar getiDlugar();
boolean getPordefecto();
ArticulosV3 getArticuloOneway();
}
So, I was asking, is there anything i can do, to in the projection, load another projection of the other column? without the eager columns? Like, doing a projection in the projection would solve it?
Or is there anything i can do?
The one that loads:
@JoinColumn(name = "ID_lugar", referencedColumnName = "ID")
@ManyToOne(optional = false)
@JsonView(JsonViews.Summary.class)
private Lugar iDlugar;
(No eager tables in Lugar)
The one that doesn't:
@JoinColumn(name = "articulo_oneway", referencedColumnName = "ID")
@NotFound(action = NotFoundAction.IGNORE)
@ManyToOne(optional = true)
@JsonView(JsonViews.Summary.class)
private ArticulosV3 articuloOneway;
(Many eagers in this one)
Removing the eagers in ArtivulosV3 would not be an options
The error if needed
2024-04-25 17:09:19 [http-nio-8080-exec-2] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[0]->$Proxy349["articuloOneway"]->com.clickrent.backoffice.ws.entities.ArticulosV3["articulosUbicacion"]->org.hibernate.collection.internal.PersistentBag[0]->com.clickrent.backoffice.ws.entities.ArticulosUbicacion["idUbicaciones"]->com.clickrent.backoffice.ws.entities.Ubicaciones_$$_jvst1a7_9e["handler"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[0]->$Proxy349["articuloOneway"]->com.clickrent.backoffice.ws.entities.ArticulosV3["articulosUbicacion"]->org.hibernate.collection.internal.PersistentBag[0]->com.clickrent.backoffice.ws.entities.ArticulosUbicacion["idUbicaciones"]->com.clickrent.backoffice.ws.entities.Ubicaciones_$$_jvst1a7_9e["handler"])
Thanks!
The error correspond to a serialization error, due to a non-serializable object is being passed as a response body of the API, which fails to write the HTTP message for the response body (there's no compatible serializer for the proxy) and that Jackson isn't accessing getters, but fields.
So, I was asking, is there anything i can do, to in the projection, load another projection of the other column? without the eager columns? Like, doing a projection in the projection would solve it?
It doesn't really matter. The problem is that at least one object that is referenced in the list returned by the controller, is a proxy.
To your question:
Or is there anything i can do?
I recommend you to separate concerns using the DTO pattern. When you map your projection objects to the DTOs through the getters, the data from the lazy objects is fetched and the problem is gone because DTOs are actually serializable.
For example:
// In your API controller
@GetMapping
public ResponseEntity<List<UbicacionesLugaresResponse>> getUbicacionesLugares() {
return ResponseEntity.ok(mapToResponse(service.getUbicacionesLugares()));
}
private List<UbicacionesLugaresResponse> mapToResponse(List<UbicacionesLugaresProjection> ubicacionesLugares) {
// map the objects using projection getters
}
class UbicacionesLugaresResponse {
private Integer id;
private int tipolugar;
private LugarResponse idLugar;
private boolean pordefecto;
private ArticulosV3Response articuloOneway;
//getters, setters and non-private empty constructor
}
Another approach would be registering a Jackson serializer for your UbicacionesLugaresProjection
type, or even trying to configure Jackson to perform getters access instead fields access for that type.
I hope it helps!