Rob Spoor wrote:There is one way I can think of: use MOXy instead of Jackson. That uses the declared type to do its mapping, not the actual type. I wouldn't want to use that myself though.
I've worked with MOXy when we were still using WebLogic (where it's the default JSON mapper), and due to some MOXy custom code we had we kept it when migrating to Spring Boot. It's not great though - if you want to use Spring MVC you need to build a bridge, because MOXy is built for JAX-RS. Its performance compared to Jackson or GSON is also pretty poor.
I'd do the simple thing - create a DTO or wrapper class for returning only the bare information.
Rob Spoor wrote:Please show some patience. Not everybody has a lot of time on their free Sundays. Also, please don't use any foul language in the future.
About your problem, I think this is something that some libraries (including Jackson) automatically do - they don't look at the declared type, but the actual type. They will therefore include any public property (either field or method based) that's not ignored. And that's where you should seek your solution - in ignoring properties.
I think in this case the easiest is to ignore everything by default, and only expose what you want. That means:
* Annotate your class with @JsonAutoDetect and set all visibility settings to Visibility.NONE.
* Use @JsonProperty on the fields, getters and setters you do want exposed.
Rob Spoor wrote:As far as I know, JPA doesn't support performing custom queries on entity methods. I understand that getFollowers().size() is not something you want to do, because that will indeed load all followers. I'd therefore go for an extra method on my repository that performs a count on the user entity table. Your input should then be either the full user object, or only its id. It does mean that your code will have to call a method on the repository instead of the user.
Tim Holloway wrote:Auto-wiring is used at construction time and it generally does not work well when trying to connect dynamic objects, such as data pulled from a database. At least I think that's what you are getting at.
Tim Holloway wrote:Your setup is very different than mine, and I'm not sure I really understand it.
I think you were asking if it was "wrong" to access an associated object when it was lazy-fetched and detached. It's not wrong, as such, but since the lazy object wasn't fetched before detachment, it will throw an exception. If you need to resolve an associated lazy object before detaching, there's no formal method, but simply referencing that object will fetch it and replace the dummy with the actual object. In other words, to force resolution of a Department record for an Employee, just do something throw-away like "thisEmployee.getDepartment().getId()". For collections (OneToMany, ManyToMany), iterate the collection. For best results, resolve both the forward and backward links, if they exist.
Let me describe how I do things. It's fairly simple and it has worked well for me.
I have basically 3 tiers for persistence in my JPA apps.
1. The bottom tier is the Entity classes themselves.
2. The next-level tier is DAOs. My DAOs are finders and CRUD methods for single-table operations. Or in some cases, where parent/child relationships are tightly bound, parent and child entity DAOs.
3. The top level is persistence services.
Most of my apps don't work on a single table at a time, they work on a network of related table objects. So the persistence services are responsible for making the necessary collection of data available to the non-persistence layer (business logic), and for persisting changes made to that collection of data ("working set"). Both the service tier and the DAO tier are transactional at the class level, although DAOs inherit the transaction context of the service method that calls them. To make things more predictable, DAOs are never called directly by business logic, only by persistence methods.
The service methods work with attached objects, so if I need to expand a working set (which is always detached), I'll pass that set to a service method that re-attaches, resolves whatever lazy dependencies I need resolved, and then returns a new detached instance of the working set with the new relationships in it. The service methods use the DAOs for the low-level work, so all DAOs have an EntityManager injected into them (I haven't been using the Spring CRUD repo). The service methods never use an EntityManager directly.
Tim Holloway wrote:If you use CrudRepository or JPARepository (or a subclass of one of them), then the EntityManager is used internally by their implementations. In my case, I use DAOs as repositories, so I inject an EntityManager via @PersistenceContext.
This might help: https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
Tim Holloway wrote:I'm rusty on JPA - people owe me money, so I found other things to do until they start paying me again.
However, I believe that merge() is an EntityManager method.
You'll know when you attempt to reference a detached lazy object. In fact, I think it throws an Exception if you even try.
Tim Holloway wrote:I think that "user" is a detached object. Lazy references cannot be resolved when an object is detached - in fact a dummy object is inserted in place of the lazy object or collection to alert you to that fact.
If that's what happened, you'll need to re-attach "user' by doing a JPA merge() before you can access its lazy collection of Post's. Note that merge does not return the same object back that you pass to it. Once merged, discard the original User object and use the merged User object instead.