{"id":20841497,"url":"https://github.com/wavesoftware/java-mapstruct-jpa","last_synced_at":"2025-08-17T01:33:38.611Z","repository":{"id":57745374,"uuid":"131848583","full_name":"wavesoftware/java-mapstruct-jpa","owner":"wavesoftware","description":"A set of utilities focused on mapping JPA managed entities with MapStruct","archived":false,"fork":false,"pushed_at":"2018-05-07T18:36:19.000Z","size":104,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-12T05:41:46.544Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wavesoftware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-02T12:39:17.000Z","updated_at":"2023-07-24T07:36:49.000Z","dependencies_parsed_at":"2022-08-30T17:41:46.328Z","dependency_job_id":null,"html_url":"https://github.com/wavesoftware/java-mapstruct-jpa","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/wavesoftware/java-mapstruct-jpa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wavesoftware%2Fjava-mapstruct-jpa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wavesoftware%2Fjava-mapstruct-jpa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wavesoftware%2Fjava-mapstruct-jpa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wavesoftware%2Fjava-mapstruct-jpa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wavesoftware","download_url":"https://codeload.github.com/wavesoftware/java-mapstruct-jpa/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wavesoftware%2Fjava-mapstruct-jpa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270796218,"owners_count":24647319,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T01:20:23.929Z","updated_at":"2025-08-17T01:33:38.583Z","avatar_url":"https://github.com/wavesoftware.png","language":"Java","readme":"# JPA mapping utilities for MapStruct\n\n[![Build Status](https://travis-ci.org/wavesoftware/java-mapstruct-jpa.svg?branch=master)](https://travis-ci.org/wavesoftware/java-mapstruct-jpa) [![Quality Gate](https://sonar.wavesoftware.pl/api/badges/gate?key=pl.wavesoftware.utils:mapstruct-jpa)](https://sonar.wavesoftware.pl/dashboard/index/pl.wavesoftware.utils:mapstruct-jpa) [![Coverage Status](https://coveralls.io/repos/github/wavesoftware/java-mapstruct-jpa/badge.svg?branch=master)](https://coveralls.io/github/wavesoftware/java-mapstruct-jpa?branch=master) [![Maven Central](https://img.shields.io/maven-central/v/pl.wavesoftware.utils/mapstruct-jpa.svg)](https://mvnrepository.com/artifact/pl.wavesoftware.utils/mapstruct-jpa)\n\nA set of utilities focused on mapping JPA managed entities with MapStruct. There are different utilities for different purposes and also a all-in-one utility for maximizing ease of use.\n\n## Features\n\n* Domain model graph with cycles - via `CyclicGraphContext`\n* JPA aware mapping with update capability - via `JpaMappingContext` factory\n* [N+1 problem](https://stackoverflow.com/questions/97197/what-is-the-n1-select-query-issue) solution via special uninitialized collection classes, that throws exceptions if used\n\n### Domain model graph with cycles\n\nIf you need to map a domain model with cycles in entity graph for ex.: (Pet.owner -\u003e Person, Person.pets -\u003e Pet) you can use a `CyclicGraphContext` as a MapStruct `@Context`\n\n```java\n@Mapper\ninterface PetMapper {\n  Pet map(PetData data, @Context CyclicGraphContext context);\n  PetData map(Pet pet, @Context CyclicGraphContext context);\n}\n```\n\n### JPA aware mapping with update capability\n\nIf you also need support for mapping JPA managed entities and be able to update them (not create new records) there more to be done. There is provided `JpaMappingContext` with factory. It requires couple more configuration to instantiate this context.\n\n`JpaMappingContext` factory requires:\n* Supplier of `StoringMappingContext` to handle cycles - `CyclicGraphContext` can be used here,\n* `Mappings` object that will provides mapping for given source and target class - mapping is information how to update existing object (managed entity) with data from source object,\n* `IdentifierCollector` should collect managed entity ID from source object\n\nThe easiest way to setup all of this is to extend `AbstractJpaContextProvider`, implement `IdentifierCollector` and implement a set of `MappingProvider` for each type of entity. To provide implementations of `MappingProvider` you should create update methods in your MapStruct mappers. It utilize `CompositeContext` which can incorporate any number of contexts as a composite.\n\nAll of this can be managed by some DI container like Spring or Guice.\n\n**Mapping facade as Spring service:**\n \n```java\n@Service\n@RequiredArgsConstructor\nfinal class MapperFacadeImpl implements MapperFacade {\n\n  private final PetMapper petMapper;\n  private final MapStructContextProvider\u003cCompositeContext\u003e contextProvider;\n\n  @Override\n  public PetJPA map(Pet pet) {\n    return petMapper.map(pet, contextProvider.createNewContext());\n  }\n\n  @Override\n  public Pet map(PetJPA jpa) {\n    return petMapper.map(jpa, contextProvider.createNewContext());\n  }\n}\n```\n\n**Context provider as Spring service:**\n\n```java\n@Service\n@RequiredArgsConstructor\nfinal class CompositeContextProvider extends AbstractCompositeContextProvider {\n\n  @Getter\n  private final JpaMappingContextFactory jpaMappingContextFactory;\n  private final List\u003cMappingProvider\u003c?, ?, ?\u003e\u003e mappingProviders;\n  @Getter\n  private final IdentifierCollector identifierCollector;\n\n  @Override\n  protected Iterable\u003cMappingProvider\u003e getMappingProviders() {\n    return Collections.unmodifiableSet(mappingProviders);\n  }\n\n}\n```\n\n**Example mapping provider for Pet as Spring service:**\n\n```java\n@Service\n@RequiredArgsConstructor\nfinal class PetMappingProvider implements MappingProvider\u003cPet, PetJPA, CompositeContext\u003e {\n\n  private final PetMapper petMapper;\n\n  @Override\n  public Mapping\u003cPet, PetJPA, CompositeContext\u003e provide() {\n    return AbstractCompositeContextMapping.mapperFor(\n      Pet.class, PetJPA.class,\n      petMapper::updateFromPet\n    );\n  }\n}\n```\n\n**Identifier collector implementation as Spring service:**\n\n```java\n@Service\nfinal class IdentifierCollectorImpl implements IdentifierCollector {\n  @Override\n  public Optional\u003cObject\u003e getIdentifierFromSource(Object source) {\n    if (source instanceof AbstractEntity) {\n      AbstractEntity entity = AbstractEntity.class.cast(source);\n      return Optional.ofNullable(\n        entity.getReference()\n      );\n    }\n    return Optional.empty();\n  }\n}\n```\n\n**HINT:** Complete working example in Spring can be seen in [coi-gov-pl/spring-clean-architecture hibernate module](https://github.com/coi-gov-pl/spring-clean-architecture/tree/develop/pets/persistence-hibernate/src/main/java/pl/gov/coi/cleanarchitecture/example/spring/pets/persistence/hibernate/mapper)\n \n**HINT:** An example for Guice can be seen in this repository in test packages.\n\n### N+1 problem solution via special uninitialized collection classes\n\nThe N+1 problem is wide known and prominent problem when dealing with JPA witch utilizes lazy loading of data. Solution to this is that developers should fetch only data that they will need (for ex.: using `JOIN FETCH` in JPQL). In many cases that is not enough. It easy to slip some loop when dealing with couple of records.\n\nMy solution is to detect that object is not loaded fully and provide a stub that will fail fast if data is not loaded and been tried to be used by other developer. To do that simple use `Uninitialized*` classes provided. There are `UninitializedList`, `UninitializedSet`, and `UninitializedMap`.\n\n```java\n@Mapper\ninterface PetMapper {\n  // [..]\n  default List\u003cPet\u003e petJPASetToPetList(Set\u003cPetJPA\u003e set,\n                                       @Context CompositeContext context) {\n    if (!Hibernate.isInitialized(set)) {\n      return new UninitializedList\u003c\u003e(PetJPA.class);\n    }\n    return set.stream()\n      .map(j -\u003e map(j, context))\n      .collect(Collectors.toList());\n  }\n  // [..]\n}\n```\n\n**Disclaimer:** In future we plan to provide an automatic solution using dynamic proxy objects.\n\n## Dependencies\n\n * Java \u003e= 8\n * [MapStruct JDK8](https://github.com/mapstruct/mapstruct/tree/master/core-jdk8) \u003e= 1.2.0\n * [EID Exceptions](https://github.com/wavesoftware/java-eid-exceptions) library \n\n### Contributing\n\nContributions are welcome!\n\nTo contribute, follow the standard [git flow](http://danielkummer.github.io/git-flow-cheatsheet/) of:\n\n1. Fork it\n1. Create your feature branch (`git checkout -b feature/my-new-feature`)\n1. Commit your changes (`git commit -am 'Add some feature'`)\n1. Push to the branch (`git push origin feature/my-new-feature`)\n1. Create new Pull Request\n\nEven if you can't contribute code, if you have an idea for an improvement please open an [issue](https://github.com/wavesoftware/java-mapstruct-jpa/issues).\n","funding_links":[],"categories":["\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwavesoftware%2Fjava-mapstruct-jpa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwavesoftware%2Fjava-mapstruct-jpa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwavesoftware%2Fjava-mapstruct-jpa/lists"}