mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 16:35:45 +01:00
Enable Jackson serialization features
This commit is contained in:
@@ -33,6 +33,7 @@ package sonia.scm.api.rest;
|
|||||||
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
|
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
|
||||||
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
|
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
|
||||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||||
@@ -63,6 +64,8 @@ public final class JSONContextResolver implements ContextResolver<ObjectMapper>
|
|||||||
.registerModule(new JavaTimeModule());
|
.registerModule(new JavaTimeModule());
|
||||||
mapper.setAnnotationIntrospector(createAnnotationIntrospector());
|
mapper.setAnnotationIntrospector(createAnnotationIntrospector());
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||||
|
mapper.configure(SerializationFeature.WRITE_DATES_WITH_ZONE_ID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AnnotationIntrospector createAnnotationIntrospector() {
|
private AnnotationIntrospector createAnnotationIntrospector() {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public class UserCollectionResource extends AbstractManagerResource<User, UserException> {
|
public class UserCollectionResource extends AbstractManagerResource<User, UserException> {
|
||||||
private final UserDto2UserMapper dtoToUserMapper;
|
private final UserDto2UserMapper dtoToUserMapper;
|
||||||
private final User2UserDtoMapper userToDtoMapper;
|
private final User2UserDtoMapper userToDtoMapper;
|
||||||
@@ -48,7 +49,6 @@ public class UserCollectionResource extends AbstractManagerResource<User, UserEx
|
|||||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||||
@ResponseCode(code = 500, condition = "internal server error")
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
})
|
})
|
||||||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
|
||||||
public Response getAll(@Context Request request, @Context UriInfo uriInfo, @DefaultValue("0")
|
public Response getAll(@Context Request request, @Context UriInfo uriInfo, @DefaultValue("0")
|
||||||
@QueryParam("start") int start, @DefaultValue("-1")
|
@QueryParam("start") int start, @DefaultValue("-1")
|
||||||
@QueryParam("limit") int limit, @QueryParam("sortby") String sortby,
|
@QueryParam("limit") int limit, @QueryParam("sortby") String sortby,
|
||||||
@@ -69,7 +69,6 @@ public class UserCollectionResource extends AbstractManagerResource<User, UserEx
|
|||||||
@ResponseCode(code = 500, condition = "internal server error")
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
})
|
})
|
||||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
|
||||||
public Response create(@Context UriInfo uriInfo, UserDto userDto) throws IOException, UserException {
|
public Response create(@Context UriInfo uriInfo, UserDto userDto) throws IOException, UserException {
|
||||||
User user = dtoToUserMapper.userDtoToUser(userDto, "");
|
User user = dtoToUserMapper.userDtoToUser(userDto, "");
|
||||||
manager.create(user);
|
manager.create(user);
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public class UserDto {
|
public class UserDto {
|
||||||
private boolean active;
|
private boolean active;
|
||||||
private boolean admin;
|
private boolean admin;
|
||||||
@@ -19,6 +21,6 @@ public class UserDto {
|
|||||||
private String password;
|
private String password;
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
@XmlElement(name = "_links")
|
@JsonProperty("_links")
|
||||||
private Map<String, Link> links;
|
private Map<String, Link> links;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||||
@@ -15,6 +16,8 @@ import javax.ws.rs.*;
|
|||||||
import javax.ws.rs.core.*;
|
import javax.ws.rs.core.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public class UserSubResource extends AbstractManagerResource<User, UserException> {
|
public class UserSubResource extends AbstractManagerResource<User, UserException> {
|
||||||
private final UserDto2UserMapper dtoToUserMapper;
|
private final UserDto2UserMapper dtoToUserMapper;
|
||||||
private final User2UserDtoMapper userToDtoMapper;
|
private final User2UserDtoMapper userToDtoMapper;
|
||||||
@@ -35,7 +38,6 @@ public class UserSubResource extends AbstractManagerResource<User, UserException
|
|||||||
@ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"),
|
@ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"),
|
||||||
@ResponseCode(code = 500, condition = "internal server error")
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
})
|
})
|
||||||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
|
||||||
public Response get(@Context Request request, @Context UriInfo uriInfo, @PathParam("id") String id)
|
public Response get(@Context Request request, @Context UriInfo uriInfo, @PathParam("id") String id)
|
||||||
{
|
{
|
||||||
if (SecurityUtils.getSubject().hasRole(Role.ADMIN))
|
if (SecurityUtils.getSubject().hasRole(Role.ADMIN))
|
||||||
@@ -58,7 +60,6 @@ public class UserSubResource extends AbstractManagerResource<User, UserException
|
|||||||
@ResponseCode(code = 500, condition = "internal server error")
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
})
|
})
|
||||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||||
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
|
||||||
public Response update(@Context UriInfo uriInfo,
|
public Response update(@Context UriInfo uriInfo,
|
||||||
@PathParam("id") String name, UserDto userDto)
|
@PathParam("id") String name, UserDto userDto)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,15 +30,26 @@
|
|||||||
*/
|
*/
|
||||||
package sonia.scm.api.rest;
|
package sonia.scm.api.rest;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import java.io.IOException;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
import org.junit.Test;
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,4 +150,47 @@ public class JSONContextResolverTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldWriteDate() throws JsonProcessingException {
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||||
|
LocalDateTime dateTime = LocalDateTime.parse("1998-06-13 14:40", formatter);
|
||||||
|
|
||||||
|
DateSample value = new DateSample(dateTime.toInstant(ZoneOffset.UTC));
|
||||||
|
|
||||||
|
assertEquals("{\"date\":\"1998-06-13T14:40:00Z\"}", mapper.writeValueAsString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data @AllArgsConstructor @NoArgsConstructor
|
||||||
|
private static class DateSample {
|
||||||
|
private Instant date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotWriteEmptyOptionals() throws JsonProcessingException {
|
||||||
|
OptionalSample emptyValue = new OptionalSample(Optional.empty());
|
||||||
|
OptionalSample presentValue = new OptionalSample(Optional.of("world"));
|
||||||
|
|
||||||
|
assertEquals("{}", mapper.writeValueAsString(emptyValue));
|
||||||
|
assertEquals("{\"value\":\"world\"}", mapper.writeValueAsString(presentValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReadEmptyOptionals() throws IOException {
|
||||||
|
OptionalSample value = mapper.readValue("{}", OptionalSample.class);
|
||||||
|
assertNotNull("Optional should not be null", value.getValue());
|
||||||
|
assertFalse("Optional should be set as empty", value.getValue().isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReadNonEmptyOptionals() throws IOException {
|
||||||
|
OptionalSample value = mapper.readValue("{\"value\":\"world\"}", OptionalSample.class);
|
||||||
|
assertEquals("world", value.getValue().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data @AllArgsConstructor @NoArgsConstructor
|
||||||
|
private static class OptionalSample {
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
|
private Optional<String> value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user