1

I have project in Spring Boot. I have User model, what have Profile model in relation OneToOne:

User: (Simplified)

@Entity
@Table(name = "users")
public class User extends AbstractEntity {

    @Id
    @GeneratedValue
    private Integer id;

    @NotEmpty
    @Basic(optional = false)
    @Column(nullable = false, unique = true)
    private String username;

    @Valid
    @JsonIgnore
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
    private Profile profile;

    @JsonIgnore
    public Profile getProfile() {
        return profile;
    }

    @JsonProperty
    public void setProfile(Profile profile) {
        this.profile = profile;
    }
}

Profile: (Simplified)

@Entity
@Table(name = "profiles")
public class Profile extends AbstractEntity {

    @Id
    @GeneratedValue
    private Integer id;

    @NotEmpty
    @Basic(optional = false)
    @Column(nullable = false)
    private String name;

    @NotEmpty
    @Basic(optional = false)
    @Column(nullable = false)
    private String surname;

    // Getters, setters, etc
}

My test:

 @Test
    public void createUserAndProfileReturnsCreatedStatus() throws Exception {
        final User user = Generator.generateUser();
        user.setProfile(Generator.generateProfile());
        MvcResult mvcResult = this.mockMvc.perform(
                post("/users")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(toJson(user)))
                .andExpect(status().isCreated())
                .andReturn();
    }

Problem is, when i do user.setProfile(), Profile is set into User but when i call toJson(user) its automatically ignored because of my annotations in model.

How to disable those annotations just for purpose of testing? Is it possible? I dont want to remove @JsonIgnore annotations from model, because they are there to not expose Profile when I READ user by GET /users/<id>.

Baterka
  • 3,075
  • 5
  • 31
  • 60
  • 1
    Since your test seems to be an integration test (more or less), you don't want to do that, since you're NOT expecting this output when you call the resource. – maio290 Dec 10 '18 at 17:18
  • @maio290 I expect `201 - Created` when I call `POST /users`, what create new User + Profile in database. Sure I can write JSON request body manually, but It will be pain in ass and slow to make. – Baterka Dec 10 '18 at 17:21
  • 1
    My fault, is misunderstood one part in your test. However, @JsonIgnore is as far as I remember an annotation of Jackson. You may try to serialize the object using json-b, which shouldn't heed the annotations of Jackson. – maio290 Dec 10 '18 at 17:23

1 Answers1

3

This can be achieved by utilizing Jackson's Mixin feature, where you create another class that cancels the ignore annotation. The only requirement from the mixin class is to have the same property name and type. class name is not important, nor do you need to instantiate it:

public class DoNotIgnoreProfile
{
    @JsonIgnore(false)
    private Profile profile;
}

a Jackson Module is required to tie the bean and mixin together:

@SuppressWarnings("serial")
public class DoNotIgnoreProfileModule extends SimpleModule
{
    public DoNotIgnoreProfileModule() {
        super("DoNotIgnoreProfileModule");
    }

    @Override
    public void setupModule(SetupContext context)
    {
        context.setMixInAnnotations(User.class, DoNotIgnoreProfile.class);
    }
}

now you need to register the module into an ObjectMapper and you're all set:

public string toJson(User user)
{
    try {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new DoNotIgnoreProfileModule());
        return mapper.writeValueAsString(user);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

EDIT: I just saw that ObjectMapper has an addMixin() method so the whole module setup can be skipped

Sharon Ben Asher
  • 13,849
  • 5
  • 33
  • 47