null

Liferay JAX-RS сервис: меняем имена полей в JSON

Для примера разберём такую задачу. Имеется класс UserDTO, описывающий пользователя системы, у которого есть ряд булевых признаков (isActive, isStudent, isTeacher).

@Getter
@Setter
public class UserDTO {
  private long userId;
  private String userName;
  private String firstName;
  private String middleName;
  private String lastName;
  private boolean isActive;
  private boolean isStudent;
  private boolean isTeacher;
}

И рест-сервис, который возвращает пользователя в формате JSON.

@Component(service = UserController.class)
@Path("/user")
public class UserController {
  @Reference(service = UserService.class)
  UserService userService;

  public UserController() {}
  public UserController(UserService service) {
	userService = service;
  }

  @GET
  @Path("/")
  @Produces(MediaType.APPLICATION_JSON)
  public Response getCurrentUser(@Context HttpServletRequest request) throws Exception {
	UserDTO user = userService.getUserDTO(PortalUtil.getUser(request));
	return Response.ok().entity(user).build();
  }
}

На стороне клиента фронт с помощью запроса получает пользователя и в зависимости от наличия у него признака student или teacher отображает разный контент.

<p>
  Вы вошли как {currentUser?.fullName} ({currentUser?.userName})
  {currentUser.isTeacher ? ", преподаватель" : ""}
  {currentUser.isStudent ? ", студент" : ""}
</p>

С какой проблемой мы можем столкнуться? Мы ожидаем, что имена полей в ответе сервера будут соответствовать именам полей в UserDTO, но это не так. На деле JSON объект будет выглядеть так:

{
  "userId":35970,
  "userName":"teacher",
  "firstName":"Вениамин",
  "middleName":"Станиславович",
  "lastName":"Обводный",
  "active":true,
  "student":false,
  "teacher":false,
}

Использованные нами аннотации @Getter и @Setter автоматически удалили is из имён полей при генерации get* и set* методов (например, setActive для поля isActive), а Jackson сгенерировал по ним поля JSON объекта, удалив приставку get/set.
Существует возможность задать имена полей итогового JSON явно с помощью аннотаций. Для этого нужно добавить в проект зависимость (ниже пример для Gradle на котлине).

compileOnly("com.fasterxml.jackson.core:jackson-databind:2.10.3")

Версию Jackson следует подсмотреть в исходниках Liferay (в моём случае версии 7.3.4), иначе зависимость не будет найдена.

https://github.com/liferay/liferay-portal/blob/7.3.4-ga5/modules/apps/portal-remote/portal-remote-jaxrs-whiteboard-jaxb-json/build.gradle

Добавляем аннотации.

@Getter
@Setter
public class UserDTO {
  private long userId;
  private String userName;
  private String firstName;
  private String middleName;
  private String lastName;
  @JsonProperty("isActive")
  private boolean isActive;
  @JsonProperty("isStudent")
  private boolean isStudent;
  @JsonProperty("isTeacher")
  private boolean isTeacher;
}

Теперь объект сериализуется так, как нам хотелось бы.

{
  "userId":35970,
  "userName":"teacher",
  "firstName":"Вениамин",
  "middleName":"Станиславович",
  "lastName":"Обводный",
  "isActive":true,
  "isStudent":false,
  "isTeacher":false,
}

Основной подводный камень в данном случае - поиск правильной версии зависимости. Не стоит пытаться делать зависимость уровня implementation и тащить её вместе с модулем, т.к. это может привести к другим ошибкам неразрешённых зависимостей, куда проще использовать библиотеки, уже имеющиеся в Liferay.

 

 

Вперед