ExerciseWarm-up
Warm-up
Leak a column you never exposed
10 minjunior0–15 yrs
One concept, guided. Near-impossible to fail.
What this teaches
- A serialiser walks every field, including the ones you did not mean to publish
- Adding a column to a table changes the API with no code change
- A bidirectional mapping is a cycle, and a serialiser has no idea where to stop
- Serialising a lazy association issues a query, outside the transaction
Starter
Starter.java
import java.lang.reflect.*;
import java.util.*;
/**
* Warm-up: publish a password hash without meaning to.
*
* No Jackson and no Hibernate. A serialiser is, for this purpose, a thing that
* reflects over fields and emits all of them — which is the only property that
* matters here.
*/
public class Starter {
public static void main(String[] args) throws Exception {
// TODO 1: write serialise(Object) using reflection over
// getDeclaredFields(). Emit every field as a JSON key. Recurse into
// objects and collections, and pass a depth so you can stop.
//
// Note: getDeclaredFields() order is unspecified by the JLS. It is
// stable in practice for a given class file, and worth knowing you are
// relying on that.
// TODO 2: write a User entity with id, email and displayName. Serialise
// it. This is your API response.
// TODO 3: now add passwordHash and internalNotes to the entity, as a
// migration would. Do not touch the serialising code. Print the JSON
// again and compare.
//
// Write one sentence about which review would have caught that.
// TODO 4: define a record UserResponse(long id, String displayName),
// populate it from the entity, and serialise that instead. Add another
// field to the entity and confirm the response does not change.
// TODO 5: build a bidirectional pair — Author has books, Book has an
// author — and serialise the author. You will need a depth limit.
// Say what Jackson does instead of stopping, and why the mapping is
// still not the thing that is wrong.
// TODO 6: give the entity a lazy field: a wrapper holding a Supplier
// that increments a counter the first time it is read. Serialise the
// entity and print the counter before and after.
//
// Then say where that query happens relative to the transaction, and
// which of your timers would have seen it.
// TODO 7: finally, the direction people forget. If a controller
// accepted this entity as a request body, list the fields a caller
// could set. Say what setting `id` would do to a save().
}
}Run it locally:
cd exercises/java/jpa-hibernate/entity-at-the-boundary/01-warmup
javac Starter.java -d /tmp/out && java -cp /tmp/out StarterDone when
- You added a field to an entity and watched it appear in the JSON
- You produced the recursion, and can say what real Jackson does instead of stopping
- You showed serialisation triggering a lazy load
- You showed a DTO leaving the JSON unchanged when the entity gains a field
← Back to Should you return a JPA entity from a REST controller?