Возьмите класс, подобный этому:
@XmlRootElement
public class Person extends AbstractEntity<Person> {
public Integer id; // Actually in AbstractEntity
public Person parent;
public Person partner;
}
С PersonResource.class, содержащим соответствующий @Path
, @GET
и подобный метод - с базовым классом, который имеет согласованный метод "// {id}"
Это производит JSON, похожий на:
{
"id": 1,
"parent": {
"id": 2
},
"partner": {
"id": 3
}
}
Вместо этого я бы хотел, чтобы он выглядел следующим образом (или похожим, чтобы объекты, на которые ссылаются, не были частично или полностью «встроены»):
{
"id": 1,
"parent": "/people/2",
"partner": "/people/3"
}
И быть прозрачным для сущности и других классов.
Мое текущее решение - создать новую аннотацию:
@Retention(RUNTIME)
@Target(TYPE)
public @interface AssignedResource {
Class<? extends AbstractResource<? extends AbstractEntity<?>>> resource();
}
Затем аннотируйте каждый класс сущности этим, «указывая» на класс Resource.
Затем, в случае WriterInterceptor
:
final AbstractEntity<?> ent = (AbstractEntity<?>) context.getEntity();
...
for (final Field entFields : ent.getClass().getDeclaredFields())
try {
if (entFields.getType().isAnnotationPresent(AssignedResource.class))
context.getHeaders().add(HttpHeaders.LINK,
Link.fromPath(entFields.getType()
.getAnnotation(AssignedResource.class)
.resource()
.getAnnotation(Path.class)
.value() + "/" + ((AbstractEntity<?>) entFields.get(ent)).getId())
.rel(entFields.getName())
.build());
} catch (final IllegalArgumentException | IllegalAccessException e) {
throw new InternalServerErrorException(e);
}
Что работает, добавив несколько заголовков Link :. Но это хаки.
Есть ли лучший (#define лучше, более надежный в идеале использование фреймворка и требующий минимальных изменений для каждого класса) способ?