3

I am new to Micronaut, and I have been following the documentation to set up a simple REST application. I thought I would start with a simple Many-to-Many relationship. Everything seemed to be working. The Database tables are being generated at startup correctly, and the endpoint is returning the pageable items but NOT the nested list of Offers even though I'm including an eager fetch annotation. What am I missing? :-( I can not figure out why.

Here's what I have...

Item Controller:

@Get(value = "/{?args*}")
    public Page<ItemDTO> list(@Valid Pageable args) {
        return itemRepository.findAllOrderByName(Pageable.from(args.getNumber(), args.getSize(), args.getSort() ));
    }

Item Entity:

@Entity
@Table(name = "item")
public class Item {

    public Item() {}

    public Item(@NotNull String name) {
        this.name = name;
    }

    public static ItemDTO toDTO(Item item) {
        return new ItemDTO(item);
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Version
    private Long version;

    @NotNull
    @Column(name = "name", nullable = false, unique = true)
    private String name;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "item_offer",
            joinColumns = @JoinColumn(name = "item_id"),
            inverseJoinColumns = @JoinColumn(name = "offer_id"))
    private Set<Offer> offers = new HashSet<>();

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Set<Offer> getOffers() {
        return offers;
    }

    public Item setOffers(Set<Offer> offers) {
        this.offers = offers;
        return this;
    }

    public Item addOffer(Offer offer) {
        offers.add(offer);
        offer.getItems().add(this);
        return this;
    }

}

Item DTO:

@Introspected
public class ItemDTO {

    @NotNull
    private String name;

    private Set<OfferDTO> offers = new HashSet<>();

    public ItemDTO() {
    }

    public ItemDTO(String name) {
        this.name = name;
    }

    public ItemDTO(Item item) {
        this.name = item.getName();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Offer Entity:

@Entity
@Table(name = "offer")
public class Offer {

    public Offer() { }

    public Offer(String name) {
        this.name = name;
    }

    public static OfferDTO toDTO(Offer offer) {
        return new OfferDTO(offer);
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Version
    private Long version;

    @Column(name = "name", nullable = false, unique = true)
    private String name;

    @ManyToMany(mappedBy = "offers", fetch = FetchType.EAGER)
    private Set<Item> items = new HashSet<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Item> getItems() {
        return items;
    }

    public void setItems(Set<Item> items) {
        this.items = items;
    }
}

Offer DTO:

@Introspected
public class OfferDTO {

    @NotNull
    private String name;

    public OfferDTO() {
    }

    public OfferDTO(String name) {
        this.name = name;
    }

    public OfferDTO(Offer offer) {
        this.name = offer.getName();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

ItemRepository:

import io.micronaut.data.model.Page;
import io.micronaut.data.model.Pageable;
import io.micronaut.data.repository.PageableRepository;
import knitwizzs.domains.Item;
import knitwizzs.dtos.ItemDTO;

public interface ItemRepository extends PageableRepository<Item, Long> {

    Page<ItemDTO> findAllOrderByName(Pageable pageable);

}

This is the output I'm getting:

{
"content": [
{
"name": "Item name one"
},
{
"name": "Item name two"
}
],
"pageable": {
"number": 0,
"sort": {
"sorted": false
},
"size": 100,
"offset": 0,
"sorted": false
},
"totalSize": 2,
"totalPages": 1,
"empty": false,
"size": 100,
"offset": 0,
"pageNumber": 0,
"numberOfElements": 2
}

So no sign of the nested offers?

That's it. As I'm utilising Micronaut data, I assumed it would work. Obviously I have missed something.

Thank you in advance for any helpful information.

AndyRED
  • 331
  • 1
  • 3
  • 15
  • Can you add the code for itemRepository? Usually repositories return an entity type but your repostory seems to return the ItemDTO. So where is the mapping between entity -> dto happening? – saw303 Apr 25 '20 at 12:23
  • 1
    Hi Micronaut automatically maps to the dto equivalent when you annotate the DTO with Introspected. – AndyRED Apr 25 '20 at 15:37
  • Add my item repository too, but this simply extends the pageable repo with an additional find method. – AndyRED Apr 25 '20 at 16:07
  • Oh just discovered this... https://github.com/micronaut-projects/micronaut-data/issues/184 :-( :-( – AndyRED Apr 25 '20 at 16:15

1 Answers1

1

The @JsonIgnore annotation will exclude this field from the JSON output, since it is effectively ignored during serialization.

So you can just change your field in the ItemDTO class from:

@JsonIgnore
private Set<OfferDTO> offers = new HashSet<>();

to:

private Set<OfferDTO> offers = new HashSet<>();
  • Hi @Pieterjan Deconinck. Thank you for your response - Sorry yes, just noticed that I left this in. Taking it out, rebuilding the project and running does not change the output. I still see no offers :-( – AndyRED Apr 25 '20 at 15:55
  • Did you already check that the call to the repository return the offers? It can be either an issue in fetching the data from the repository, or an issue in serializing the data. So I would check the repository first, to make sure it behaves as you expect. – Pieterjan Deconinck Apr 25 '20 at 17:42
  • Yes already checked that the Offers were being returned and they were. I return the return types back to the Entities for both Item and Offer and the expected result was output. I think this confirms that there is a problem with nested DTOs. Not the solution I wanted as I want to be able to easily cherrypick from the properties by using DTOs. I believe Graeme Rocher is looking at bulding this feature in soon as discussed here... github.com/micronaut-projects/micronaut-data/issues/184 – AndyRED Apr 26 '20 at 19:10