APIv1Mapper.java

/*
 * Copyright 2024 Global Crop Diversity Trust
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.genesys.server.api.v1.mapper;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;

import javax.validation.constraints.NotNull;

import org.genesys.blocks.model.ClassPK;
import org.genesys.blocks.security.SecurityContextUtil;
import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.blocks.security.serialization.Permissions;
import org.genesys.blocks.util.JsonSidConverter.SidProvider;
import org.genesys.filerepository.model.RepositoryFile;
import org.genesys.filerepository.model.RepositoryImage;
import org.genesys.server.api.v1.mapper.APIv1Mapper.DataMappingsConfig.IgnoreAudit;
import org.genesys.server.api.v1.mapper.APIv1Mapper.DataMappingsConfig.IgnorePermissions;
import org.genesys.server.api.v1.mapper.APIv1Mapper.DataMappingsConfig.IncludePermissions;
import org.genesys.server.api.v1.mapper.APIv1Mapper.DataMappingsConfig.IsPublic;
import org.genesys.server.api.v1.model.ActivityPost;
import org.genesys.server.api.v1.model.Article;
import org.genesys.server.api.v1.model.ClassPKInfo;
import org.genesys.server.api.v1.model.Crop;
import org.genesys.server.api.v1.model.ControlledVocabularyInfo;
import org.genesys.server.api.v1.model.CropDetails;
import org.genesys.server.api.v1.model.Dataset;
import org.genesys.server.api.v1.model.DatasetCreatorInfo;
import org.genesys.server.api.v1.model.DatasetInfo;
import org.genesys.server.api.v1.model.DatasetLocationInfo;
import org.genesys.server.api.v1.model.Descriptor;
import org.genesys.server.api.v1.model.DescriptorInfo;
import org.genesys.server.api.v1.model.DescriptorList;
import org.genesys.server.api.v1.model.DescriptorListInfo;
import org.genesys.server.api.v1.model.MaterialRequest;
import org.genesys.server.api.v1.model.MaterialSubRequest;
import org.genesys.server.api.v1.model.MaterialSubRequestInfo;
import org.genesys.server.api.v1.model.Menu;
import org.genesys.server.api.v1.model.MenuInfo;
import org.genesys.server.api.v1.model.MenuItem;
import org.genesys.server.api.v1.model.PartnerInfo;
import org.genesys.server.api.v1.model.RepositoryFileInfo;
import org.genesys.server.api.v1.model.RepositoryImageInfo;
import org.genesys.server.api.v1.model.VocabularyTerm;
import org.genesys.server.api.v1.model.VocabularyTermInfo;
import org.genesys.server.model.Partner;
import org.genesys.server.model.dataset.DatasetCreator;
import org.genesys.server.model.dataset.DatasetLocation;
import org.genesys.server.model.vocab.ControlledVocabulary;
import org.genesys.server.service.ActivityPostTranslationService.TranslatedActivityPost;
import org.genesys.server.service.ArticleTranslationService.TranslatedArticle;
import org.genesys.server.service.CropTranslationService;
import org.genesys.server.service.DatasetTranslationService;
import org.genesys.server.service.DescriptorListTranslationService;
import org.genesys.server.service.DescriptorTranslationService;
import org.genesys.server.service.MenuItemTranslationService.TranslatedMenuItem;
import org.genesys.server.service.VocabularyTermTranslationService;
import org.mapstruct.BeanMapping;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.MapperConfig;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.FIELD, config = APIv1Mapper.DataMappingsConfig.class)
public abstract class APIv1Mapper {

	public <A, B> B[] map(@NotNull A[] source, @NotNull Function<A, B> mapper, @NotNull B[] array) {
		var res = new ArrayList<B>(source.length);
		for (A a : source) {
			res.add(mapper.apply(a));
		}
		return res.toArray(array);
	}

	public <A, B> List<B> map(@NotNull Collection<A> source, @NotNull Function<A, B> mapper) {
		var res = new ArrayList<B>(source.size());
		source.forEach(x -> res.add(mapper.apply(x)));
		return res;
	}

	public <A, B> Page<B> map(@NotNull Page<A> source, @NotNull Function<A, B> mapper) {
		return source.map(mapper);
	}

	@Autowired
	private SidProvider sidNameProvider;

	@Named("getAclSid")
	protected String getAclSid(Long id) {
		if (id == null) {
			// Don't write SID name
			return null;
		}
		return sidNameProvider == null ? id.toString() : sidNameProvider.getSidName(id);
	}

	@Named("isPublic")
	static boolean isPublic(AclAwareModel model) {
		if (model.getId() == null) {
			// Don't write permissions for non-persisted objects
			return false;
		}

		try {
			return SecurityContextUtil.anyoneHasPermission(model, "READ");
		} catch (Throwable e) {
			return false;
		}
	}

	@Named("getPermissions")
	static Permissions getPermissions(AclAwareModel model) {
		if (model.getId() == null) {
			// Don't write permissions for non-persisted objects
			return null;
		}

		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null) {
			return new Permissions().grantNone();
		}
		Permissions perms = new Permissions();
		try {
			perms.isPublic = SecurityContextUtil.anyoneHasPermission(model, "READ");
		} catch (Throwable e) {
			perms.isPublic = false;
		}

		if (SecurityContextUtil.hasRole("ADMINISTRATOR")) {
			perms.grantAll();
		} else {
			try {
				perms.create = SecurityContextUtil.hasPermission(authentication, model, BasePermission.CREATE);
				perms.read = SecurityContextUtil.hasPermission(authentication, model, BasePermission.READ);
				perms.write = SecurityContextUtil.hasPermission(authentication, model, BasePermission.WRITE);
				perms.delete = SecurityContextUtil.hasPermission(authentication, model, BasePermission.DELETE);
				perms.manage = SecurityContextUtil.hasPermission(authentication, model, BasePermission.ADMINISTRATION);
			} catch (Throwable e) {
				throw new IllegalArgumentException("Could not read current permissions " + e.getMessage(), e);
			}
		}
		return perms;
	}

	@MapperConfig
	interface DataMappingsConfig {

		@Retention(RetentionPolicy.CLASS)
		@Mapping(source = "createdBy", target = "createdBy", qualifiedByName = "getAclSid")
		@Mapping(source = "lastModifiedBy", target = "lastModifiedBy", qualifiedByName = "getAclSid")
		public @interface AuditNames { }

		@Retention(RetentionPolicy.CLASS)
		@Mapping(target = "createdBy", ignore = true)
		@Mapping(target = "createdDate", ignore = true)
		@Mapping(target = "lastModifiedBy", ignore = true)
		@Mapping(target = "lastModifiedDate", ignore = true)
		public @interface IgnoreAudit { }

		@Retention(RetentionPolicy.CLASS)
		@Mapping(target = "public", source = ".", qualifiedByName = "isPublic")
		public @interface IsPublic { }

		@Retention(RetentionPolicy.CLASS)
		@Mapping(target = "_permissions", source = ".", qualifiedByName = "getPermissions")
		public @interface IncludePermissions { }

		@Retention(RetentionPolicy.CLASS)
		@Mapping(target = "_permissions", ignore = true)
		public @interface IgnorePermissions { }
	}

	@Mapping(target = "lang", ignore = true)
	public abstract Article map(org.genesys.server.model.impl.Article article);
	
	@Mapping(target = "active", constant = "true")
	@Mapping(target = "createdBy", ignore = true)
	@Mapping(target = "createdDate", ignore = true)
	@Mapping(target = "lastModifiedBy", ignore = true)
	@Mapping(target = "lastModifiedDate", ignore = true)
	@Mapping(target = "langs", ignore = true)
	@Mapping(target = "originalLanguageTag", constant = "en")
	public abstract org.genesys.server.model.impl.Article map(Article article);

	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "template", source = "entity.template")
	@Mapping(target = "slug", source = "entity.slug")
	@Mapping(target = "targetId", source = "entity.targetId")
	@Mapping(target = "classPk", source = "entity.classPk")
	@Mapping(target = "publishDate", source = "entity.publishDate")
	@Mapping(target = "expirationDate", source = "entity.expirationDate")
	@Mapping(target = "lang", expression = "java(article.translation == null ? article.entity.getOriginalLanguageTag() : article.translation.getLanguageTag())")
	@Mapping(target = "body", expression = "java(article.translation == null ? article.entity.getBody() : article.translation.getBody())")
	@Mapping(target = "summary", expression = "java(article.translation == null ? article.entity.getSummary() : article.translation.getSummary())")
	@Mapping(target = "title", expression = "java(article.translation == null ? article.entity.getTitle() : article.translation.getTitle())")
	public abstract Article map(TranslatedArticle article);

	public abstract ClassPKInfo mapInfo(ClassPK classPk);

	@Mapping(target = "lang", ignore = true)
	public abstract ActivityPost map(org.genesys.server.model.impl.ActivityPost post);

	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "createdBy", expression = "java(getAclSid(post.entity.getCreatedBy()))")
	@Mapping(target = "createdDate", source = "entity.createdDate")
	@Mapping(target = "lastModifiedBy", expression = "java(getAclSid(post.entity.getLastModifiedBy()))")
	@Mapping(target = "lastModifiedDate", source = "entity.lastModifiedDate")
	@Mapping(target = "publishDate", source = "entity.publishDate")
	@Mapping(target = "expirationDate", source = "entity.expirationDate")
	@Mapping(target = "coverImage", source = "entity.coverImage")
	@Mapping(target = "lang", expression = "java(post.translation == null ? post.entity.getOriginalLanguageTag() : post.translation.getLanguageTag())")
	@Mapping(target = "body", expression = "java(post.translation == null ? post.entity.getBody() : post.translation.getBody())")
	@Mapping(target = "summary", expression = "java(post.translation == null ? post.entity.getSummary() : post.translation.getSummary())")
	@Mapping(target = "title", expression = "java(post.translation == null ? post.entity.getTitle() : post.translation.getTitle())")
	public abstract ActivityPost map(TranslatedActivityPost post);

	@IncludePermissions
	public abstract org.genesys.server.api.v1.model.RepositoryImage map(RepositoryImage repositoryImage);

	@Mapping(target = "apply", ignore = true)
	@Mapping(target = "folder", ignore = true)
	@Mapping(target = "identifier", ignore = true)
	@Mapping(target = "filename", ignore = true)
	@Mapping(target = "metadataFilename", ignore = true)
	@Mapping(target = "storageFolder", ignore = true)
	@IgnoreAudit
	public abstract RepositoryImage map(org.genesys.server.api.v1.model.RepositoryImage dto);

	@IsPublic
	public abstract RepositoryImageInfo mapInfo(RepositoryImage repositoryImage);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract RepositoryImage mapInfo(RepositoryImageInfo repositoryImage);

	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "active", source = "entity.active")
	@Mapping(target = "menu", source = "entity.menu")
	@Mapping(target = "orderIndex", source = "entity.orderIndex")
	@Mapping(target = "target", source = "entity.target")
	@Mapping(target = "url", source = "entity.url")
	// @Mapping(target = "lang", expression = "java(menuItem.translation == null ? menuItem.entity.getOriginalLanguageTag() : menuItem.translation.getLanguageTag())")
	@Mapping(target = "text", expression = "java(menuItem.translation == null ? menuItem.entity.getText() : menuItem.translation.getText())")
	@Mapping(target = "title", expression = "java(menuItem.translation == null ? menuItem.entity.getTitle() : menuItem.translation.getTitle())")
	public abstract MenuItem map(TranslatedMenuItem menuItem);

	public abstract MenuItem map(org.genesys.server.model.impl.MenuItem menuItem);

	@Mapping(target = "langs", ignore = true)
	@IgnoreAudit
	@Mapping(target = "originalLanguageTag", constant = "en")
	public abstract org.genesys.server.model.impl.MenuItem map(MenuItem menuItem);

	public abstract Menu map(org.genesys.server.model.impl.Menu menu);

	public abstract MenuInfo mapInfo(org.genesys.server.model.impl.Menu menu);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	public abstract org.genesys.server.model.impl.Menu mapInfo(MenuInfo menu);

	public abstract CropDetails map(org.genesys.server.service.CropService.CropDetails details);

	@Mapping(target = "_class", expression = "java(crop.getClass().getSimpleName())")
	@IgnorePermissions
	public abstract Crop map(org.genesys.server.model.impl.Crop crop);

	@Mapping(target = "originalLanguageTag", constant = "en")
	@Mapping(target = "langs", ignore = true)
	public abstract org.genesys.server.model.impl.Crop map(Crop crop);

	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "active", source = "entity.active")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "createdBy", expression = "java(getAclSid(crop.entity.getCreatedBy()))")
	@Mapping(target = "createdDate", source = "entity.createdDate")
	@Mapping(target = "lastModifiedBy", expression = "java(getAclSid(crop.entity.getLastModifiedBy()))")
	@Mapping(target = "lastModifiedDate", source = "entity.lastModifiedDate")
	@Mapping(target = "rdfUri", source = "entity.rdfUri")
	@Mapping(target = "shortName", source = "entity.shortName")
	@Mapping(target = "otherNames", source = "entity.otherNames")
	@Mapping(target = "name", source = "entity.name")
	@Mapping(target = "annex1", source = "entity.annex1")
	@Mapping(target = "description", expression = "java(crop.translation == null ? crop.entity.getDescription() : crop.translation.getDescription())")
	@Mapping(target = "_class", expression = "java(crop.entity.getClass().getSimpleName())")
	@Mapping(target = "_permissions", expression = "java(new org.genesys.blocks.security.serialization.Permissions().grantNone())")
	public abstract Crop map(CropTranslationService.TranslatedCrop crop);
	public abstract ControlledVocabularyInfo mapInfo(ControlledVocabulary controlledVocabulary);
	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract ControlledVocabulary mapInfo(ControlledVocabularyInfo info);

	@Mapping(target = "lang", source = "originalLanguageTag")
	@IncludePermissions
	public abstract Descriptor map(org.genesys.server.model.traits.Descriptor descriptor);
	
	@Mapping(target = "originalLanguageTag", source = "lang")
	@Mapping(target = "langs", ignore = true)
	@Mapping(target = "datasets", ignore = true)
	@Mapping(target = "descriptorLists", ignore = true)
	@Mapping(target = "apply", ignore = true)
	public abstract org.genesys.server.model.traits.Descriptor map(Descriptor descriptor);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "uuid", source = "entity.uuid")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "createdBy", expression = "java(getAclSid(descriptor.entity.getCreatedBy()))")
	@Mapping(target = "createdDate", source = "entity.createdDate")
	@Mapping(target = "lastModifiedBy", expression = "java(getAclSid(descriptor.entity.getLastModifiedBy()))")
	@Mapping(target = "lastModifiedDate", source = "entity.lastModifiedDate")
	@Mapping(target = "versionTag", source = "entity.versionTag")
	@Mapping(target = "dataType", source = "entity.dataType")
	@Mapping(target = "key", source = "entity.key")
	@Mapping(target = "publisher", source = "entity.publisher")
	@Mapping(target = "state", source = "entity.state")
	@Mapping(target = "integerOnly", source = "entity.integerOnly")
	@Mapping(target = "minValue", source = "entity.minValue")
	@Mapping(target = "maxValue", source = "entity.maxValue")
	@Mapping(target = "uom", source = "entity.uom")
	@Mapping(target = "columnName", source = "entity.columnName")
	@Mapping(target = "bibliographicCitation", source = "entity.bibliographicCitation")
	@Mapping(target = "vocabulary", source = "entity.vocabulary")
	@Mapping(target = "terms", source = "entity.terms")
	@Mapping(target = "owner", source = "entity.owner")
	@Mapping(target = "crop", source = "entity.crop")
	@Mapping(target = "category", source = "entity.category")
	@Mapping(target = "image", source = "entity.image")
	@Mapping(target = "firstPublishedDate", source = "entity.firstPublishedDate")
	@Mapping(target = "lang", expression = "java(descriptor.translation == null ? descriptor.entity.getOriginalLanguageTag() : descriptor.translation.getLanguageTag())")
	@Mapping(target = "title", expression = "java(descriptor.translation == null ? descriptor.entity.getTitle() : descriptor.translation.getTitle())")
	@Mapping(target = "description", expression = "java(descriptor.translation == null ? descriptor.entity.getDescription() : descriptor.translation.getDescription())")
	public abstract Descriptor map(DescriptorTranslationService.TranslatedDescriptor descriptor);

	public abstract DescriptorInfo mapInfo(org.genesys.server.model.traits.Descriptor descriptor);
	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract org.genesys.server.model.traits.Descriptor mapInfo(DescriptorInfo info);

	@IncludePermissions
	public abstract DescriptorList map(org.genesys.server.model.traits.DescriptorList descriptorList);

	@IncludePermissions
	public abstract DescriptorListInfo mapInfo(org.genesys.server.model.traits.DescriptorList descriptorList);

	@IncludePermissions
	@Mapping(target = "language", source = "originalLanguageTag")
	public abstract DatasetInfo mapInfo(org.genesys.server.model.dataset.Dataset dataset);

	@Mapping(target = "langs", ignore = true)
	@Mapping(target = "descriptors", ignore = true)
	@Mapping(target = "originalLanguageTag", constant = "en")
	public abstract org.genesys.server.model.traits.DescriptorList map(DescriptorList descriptorList);

	@IgnorePermissions
	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "uuid", source = "entity.uuid")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "active", source = "entity.active")
	@Mapping(target = "createdBy", expression = "java(getAclSid(descriptorList.entity.getCreatedBy()))")
	@Mapping(target = "createdDate", source = "entity.createdDate")
	@Mapping(target = "lastModifiedBy", expression = "java(getAclSid(descriptorList.entity.getLastModifiedBy()))")
	@Mapping(target = "lastModifiedDate", source = "entity.lastModifiedDate")
	@Mapping(target = "versionTag", source = "entity.versionTag")
	@Mapping(target = "state", source = "entity.state")
	@Mapping(target = "url", source = "entity.url")
	@Mapping(target = "bibliographicCitation", source = "entity.bibliographicCitation")
	@Mapping(target = "owner", source = "entity.owner")
	@Mapping(target = "publisher", source = "entity.publisher")
	@Mapping(target = "crop", source = "entity.crop")
	@Mapping(target = "firstPublishedDate", source = "entity.firstPublishedDate")
	@Mapping(target = "title", expression = "java(descriptorList.translation == null ? descriptorList.entity.getTitle() : descriptorList.translation.getTitle())")
	@Mapping(target = "description", expression = "java(descriptorList.translation == null ? descriptorList.entity.getDescription() : descriptorList.translation.getDescription())")
	public abstract DescriptorList map(DescriptorListTranslationService.TranslatedDescriptorList descriptorList);

	public abstract PartnerInfo mapInfo(Partner partner);
	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract Partner mapInfo(PartnerInfo info);

	public abstract VocabularyTerm map(org.genesys.server.model.vocab.VocabularyTerm term);

	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "code", source = "entity.code")
	@Mapping(target = "descriptor", source = "entity.descriptor")
	@Mapping(target = "vocabulary", source = "entity.vocabulary")
	@Mapping(target = "title", expression = "java(term.translation == null ? term.entity.getTitle() : term.translation.getTitle())")
	@Mapping(target = "description", expression = "java(term.translation == null ? term.entity.getDescription() : term.translation.getDescription())")
	public abstract VocabularyTerm map(VocabularyTermTranslationService.TranslatedVocabularyTerm term);
	
	public abstract VocabularyTermInfo mapInfo(org.genesys.server.model.vocab.VocabularyTerm term);

	@Mapping(target = "originalLanguageTag", constant = "en")
	@Mapping(target = "langs", ignore = true)
	@Mapping(target = "descriptor", ignore = true)
	@Mapping(target = "vocabulary", ignore = true)
	public abstract org.genesys.server.model.vocab.VocabularyTerm mapInfo(VocabularyTermInfo info);

	@IncludePermissions
	@Mapping(target = "language", source = "originalLanguageTag")
	public abstract Dataset map(org.genesys.server.model.dataset.Dataset dataset);

	@Mapping(target = "originalLanguageTag", source = "language")
	@Mapping(target = "langs", ignore = true)
	@Mapping(target = "accessionRefs", ignore = true)
	@Mapping(target = "versions", ignore = true)
	public abstract org.genesys.server.model.dataset.Dataset map(Dataset dataset);

	public abstract RepositoryFileInfo mapInfo(RepositoryFile file);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract RepositoryFile mapInfo(RepositoryFileInfo info);

	public abstract DatasetCreatorInfo mapInfo(DatasetCreator creator);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract DatasetCreator mapInfo(DatasetCreatorInfo info);

	public abstract DatasetLocationInfo mapInfo(DatasetLocation location);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract DatasetLocation mapInfo(DatasetLocationInfo info);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(target = "id", source = "entity.id")
	@Mapping(target = "uuid", source = "entity.uuid")
	@Mapping(target = "version", source = "entity.version")
	@Mapping(target = "createdBy", expression = "java(getAclSid(dataset.entity.getCreatedBy()))")
	@Mapping(target = "createdDate", source = "entity.createdDate")
	@Mapping(target = "lastModifiedBy", expression = "java(getAclSid(dataset.entity.getLastModifiedBy()))")
	@Mapping(target = "lastModifiedDate", source = "entity.lastModifiedDate")
	@Mapping(target = "active", source = "entity.active")
	@Mapping(target = "current", source = "entity.current")
	@Mapping(target = "owner", source = "entity.owner")
	@Mapping(target = "descriptors", source = "entity.descriptors")
	@Mapping(target = "repositoryFiles", source = "entity.repositoryFiles")
	@Mapping(target = "creators", source = "entity.creators")
	@Mapping(target = "locations", source = "entity.locations")
	@Mapping(target = "startDate", source = "entity.startDate")
	@Mapping(target = "endDate", source = "entity.endDate")
	@Mapping(target = "accessionCount", source = "entity.accessionCount")
	@Mapping(target = "descriptorCount", source = "entity.descriptorCount")
	@Mapping(target = "crops", source = "entity.crops")
	@Mapping(target = "versionTag", source = "entity.versionTag")
	@Mapping(target = "format", source = "entity.format")
	@Mapping(target = "subject", source = "entity.subject")
	@Mapping(target = "rights", source = "entity.rights")
	@Mapping(target = "source", source = "entity.source")
	@Mapping(target = "created", source = "entity.created")
	@Mapping(target = "firstPublishedDate", source = "entity.firstPublishedDate")
	@Mapping(target = "state", source = "entity.state")
	@Mapping(target = "currentVersion", source = "entity.currentVersion")
	@Mapping(target = "language", expression = "java(dataset.translation == null ? dataset.entity.getOriginalLanguageTag() : dataset.translation.getLanguageTag())")
	@Mapping(target = "title", expression = "java(dataset.translation == null ? dataset.entity.getTitle() : dataset.translation.getTitle())")
	@Mapping(target = "description", expression = "java(dataset.translation == null ? dataset.entity.getDescription() : dataset.translation.getDescription())")
	public abstract Dataset map(DatasetTranslationService.TranslatedDataset dataset);

	@Mapping(target = "subRequests", source = "subrequests")
	public abstract org.genesys.server.model.genesys.MaterialRequest map(MaterialRequest request);

	@Mapping(target = "subrequests", source = "subRequests")
	public abstract MaterialRequest map(org.genesys.server.model.genesys.MaterialRequest request);

	@Mapping(target = "sourceRequest.uuid", source = "sourceRequest")
	public abstract org.genesys.server.model.genesys.MaterialSubRequest map(MaterialSubRequest materialSubRequest);

	@Mapping(target = "origin", source = "sourceRequest.origin")
	@Mapping(target = "sid", source = "sourceRequest.sid")
	@Mapping(target = "language", source = "sourceRequest.language")
	@Mapping(target = "sourceRequest", source = "sourceRequest.uuid")
	public abstract MaterialSubRequest map(org.genesys.server.model.genesys.MaterialSubRequest materialSubRequest);

	public abstract MaterialSubRequestInfo mapInfo(org.genesys.server.model.genesys.MaterialSubRequest request);

	@BeanMapping(ignoreByDefault = true)
	@Mapping(source = "id", target = "id")
	@Mapping(source = "uuid", target = "uuid")
	public abstract org.genesys.server.model.genesys.MaterialSubRequest mapInfo(MaterialSubRequestInfo info);
}