From 34b81f18f958184f4117ff168b0840051a35a3cf Mon Sep 17 00:00:00 2001 From: Jens Pelzetter Date: Sat, 24 Sep 2022 17:12:14 +0200 Subject: [PATCH] ObjectIdResolvers for several entities --- ccm-cms/package-lock.json | 4 +- ccm-cms/package.json | 2 +- .../librecms/assets/ContactableEntity.java | 9 +++ .../assets/ContactableEntityIdResolver.java | 80 +++++++++++++++++++ .../org/librecms/assets/Organization.java | 7 ++ .../assets/OrganizationIdResolver.java | 75 +++++++++++++++++ .../main/java/org/librecms/assets/Person.java | 15 ++++ .../org/librecms/assets/PersonIdResolver.java | 74 +++++++++++++++++ .../org/librecms/assets/PersonRepository.java | 35 ++++++-- .../org/librecms/assets/PostalAddress.java | 7 ++ .../assets/PostalAddressIdResolver.java | 72 +++++++++++++++++ .../org/libreccm/categorization/Category.java | 45 +++++------ 12 files changed, 387 insertions(+), 38 deletions(-) create mode 100644 ccm-cms/src/main/java/org/librecms/assets/ContactableEntityIdResolver.java create mode 100644 ccm-cms/src/main/java/org/librecms/assets/OrganizationIdResolver.java create mode 100644 ccm-cms/src/main/java/org/librecms/assets/PersonIdResolver.java create mode 100644 ccm-cms/src/main/java/org/librecms/assets/PostalAddressIdResolver.java diff --git a/ccm-cms/package-lock.json b/ccm-cms/package-lock.json index 32572828d..670044c08 100644 --- a/ccm-cms/package-lock.json +++ b/ccm-cms/package-lock.json @@ -1,12 +1,12 @@ { "name": "@librecms/ccm-cms", - "version": "7.0.0-SNAPSHOT.2022-09-24T104753", + "version": "7.0.0-SNAPSHOT.2022-09-24T144715", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@librecms/ccm-cms", - "version": "7.0.0-SNAPSHOT.2022-09-24T104753", + "version": "7.0.0-SNAPSHOT.2022-09-24T144715", "license": "LGPL-3.0-or-later", "dependencies": { "@tiptap/core": "^2.0.0-beta.127", diff --git a/ccm-cms/package.json b/ccm-cms/package.json index 81c7eff04..680310290 100644 --- a/ccm-cms/package.json +++ b/ccm-cms/package.json @@ -1,6 +1,6 @@ { "name": "@librecms/ccm-cms", - "version": "7.0.0-SNAPSHOT.2022-09-24T104753", + "version": "7.0.0-SNAPSHOT.2022-09-24T144715", "description": "JavaScript stuff for ccm-cms", "main": "target/generated-resources/assets/@content-sections/cms-admin.js", "types": "target/generated-resources/assets/@content-sections/cms-admin.d.ts", diff --git a/ccm-cms/src/main/java/org/librecms/assets/ContactableEntity.java b/ccm-cms/src/main/java/org/librecms/assets/ContactableEntity.java index d86fbafe7..1a1a67a19 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/ContactableEntity.java +++ b/ccm-cms/src/main/java/org/librecms/assets/ContactableEntity.java @@ -18,6 +18,9 @@ */ package org.librecms.assets; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonIdentityReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; import org.hibernate.envers.Audited; @@ -46,6 +49,11 @@ import static org.librecms.CmsConstants.*; @Entity @Audited @Table(name = "CONTACTABLE_ENTITIES", schema = DB_SCHEMA) +@JsonIdentityInfo( + generator = ObjectIdGenerators.PropertyGenerator.class, + resolver = ContactableEntityIdResolver.class, + property = "uuid" +) public class ContactableEntity extends Asset { private static final long serialVersionUID = 1L; @@ -64,6 +72,7 @@ public class ContactableEntity extends Asset { */ @OneToOne @JoinColumn(name = "POSTAL_ADDRESS_ID") + @JsonIdentityReference(alwaysAsId = true) private PostalAddress postalAddress; public ContactableEntity() { diff --git a/ccm-cms/src/main/java/org/librecms/assets/ContactableEntityIdResolver.java b/ccm-cms/src/main/java/org/librecms/assets/ContactableEntityIdResolver.java new file mode 100644 index 000000000..8a10ca7b2 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/assets/ContactableEntityIdResolver.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.assets; + +import com.fasterxml.jackson.annotation.ObjectIdGenerator; +import com.fasterxml.jackson.annotation.ObjectIdResolver; +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.contentsection.AssetRepository; + +import java.io.Serializable; + +import javax.enterprise.context.RequestScoped; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +public class ContactableEntityIdResolver implements Serializable, + ObjectIdResolver { + + private static final long serialVersionUID = 1L; + + @Override + public void bindItem( + final ObjectIdGenerator.IdKey id, + final Object object + ) { + // According to the Jackson JavaDoc, this method can be used to keep + // track of objects directly in a resolver implementation. We don't need + // this here therefore this method is empty. + } + + @Override + public Object resolveId(final ObjectIdGenerator.IdKey id) { + return CdiUtil + .createCdiUtil() + .findBean(AssetRepository.class) + .findByUuidAndType( + id.key.toString(), + ContactableEntity.class + ) + .orElseThrow( + () -> new IllegalArgumentException( + String.format( + "No ContactableEntity with UUID %s found in the " + + "database", + id.key.toString() + ) + ) + ); + } + + @Override + public ObjectIdResolver newForDeserialization(final Object context) { + return new ContactableEntityIdResolver(); + } + + @Override + public boolean canUseFor(final ObjectIdResolver resolverType) { + return resolverType instanceof ContactableEntityIdResolver; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/assets/Organization.java b/ccm-cms/src/main/java/org/librecms/assets/Organization.java index 15d0d0eb3..501259279 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/Organization.java +++ b/ccm-cms/src/main/java/org/librecms/assets/Organization.java @@ -19,6 +19,8 @@ package org.librecms.assets; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import org.hibernate.envers.Audited; import org.librecms.ui.contentsections.assets.MvcAssetEditKit; import org.librecms.ui.contentsections.assets.OrganizationCreateStep; @@ -51,6 +53,11 @@ import static org.librecms.assets.AssetConstants.*; @Entity @Audited @Table(name = "ORGANIZATIONS", schema = DB_SCHEMA) +@JsonIdentityInfo( + generator = ObjectIdGenerators.PropertyGenerator.class, + resolver = OrganizationIdResolver.class, + property = "uuid" +) public class Organization extends ContactableEntity { private static final long serialVersionUID = 1L; diff --git a/ccm-cms/src/main/java/org/librecms/assets/OrganizationIdResolver.java b/ccm-cms/src/main/java/org/librecms/assets/OrganizationIdResolver.java new file mode 100644 index 000000000..19c30ae29 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/assets/OrganizationIdResolver.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.assets; + +import com.fasterxml.jackson.annotation.ObjectIdGenerator; +import com.fasterxml.jackson.annotation.ObjectIdResolver; +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.contentsection.AssetRepository; + +import java.io.Serializable; + +import javax.enterprise.context.RequestScoped; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +public class OrganizationIdResolver implements Serializable, ObjectIdResolver { + + private static final long serialVersionUID = 1L; + + @Override + public void bindItem( + final ObjectIdGenerator.IdKey id, + final Object object + ) { + // According to the Jackson JavaDoc, this method can be used to keep + // track of objects directly in a resolver implementation. We don't need + // this here therefore this method is empty. + } + + @Override + public Object resolveId(final ObjectIdGenerator.IdKey id) { + return CdiUtil + .createCdiUtil() + .findBean(AssetRepository.class) + .findByUuidAndType(id.key.toString(), Organization.class) + .orElseThrow( + () -> new IllegalArgumentException( + String.format( + "No Organization with UUID %s found in the database", + id.key.toString() + ) + ) + ); + } + + @Override + public ObjectIdResolver newForDeserialization(final Object context) { + return new OrganizationIdResolver(); + } + + @Override + public boolean canUseFor(final ObjectIdResolver resolverType) { + return resolverType instanceof OrganizationIdResolver; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/assets/Person.java b/ccm-cms/src/main/java/org/librecms/assets/Person.java index 8e9439dc9..431e7e78a 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/Person.java +++ b/ccm-cms/src/main/java/org/librecms/assets/Person.java @@ -19,6 +19,8 @@ package org.librecms.assets; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import org.hibernate.envers.Audited; import org.librecms.ui.contentsections.assets.MvcAssetEditKit; import org.librecms.ui.contentsections.assets.PersonCreateStep; @@ -35,6 +37,8 @@ import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; import javax.persistence.Table; import static org.librecms.CmsConstants.*; @@ -58,6 +62,17 @@ import static org.librecms.assets.AssetConstants.*; createStep = PersonCreateStep.class, editStep = PersonEditStep.class ) +@NamedQueries( + @NamedQuery( + name = "Person.findByUuid", + query = "SELECT p FROM Person p WHERE p.uuid = :uuid" + ) +) +@JsonIdentityInfo( + generator = ObjectIdGenerators.PropertyGenerator.class, + resolver = PersonIdResolver.class, + property = "uuid" +) public class Person extends ContactableEntity { private static final long serialVersionUID = 1L; diff --git a/ccm-cms/src/main/java/org/librecms/assets/PersonIdResolver.java b/ccm-cms/src/main/java/org/librecms/assets/PersonIdResolver.java new file mode 100644 index 000000000..7d2b02ced --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/assets/PersonIdResolver.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.assets; + +import com.fasterxml.jackson.annotation.ObjectIdGenerator; +import com.fasterxml.jackson.annotation.ObjectIdResolver; +import org.libreccm.cdi.utils.CdiUtil; + +import java.io.Serializable; + +import javax.enterprise.context.RequestScoped; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +public class PersonIdResolver implements Serializable, ObjectIdResolver { + + private static final long serialVersionUID = 1L; + + @Override + public void bindItem( + final ObjectIdGenerator.IdKey idKey, + final Object object + ) { + // According to the Jackson JavaDoc, this method can be used to keep + // track of objects directly in a resolver implementation. We don't need + // this here therefore this method is empty. + } + + @Override + public Object resolveId(final ObjectIdGenerator.IdKey id) { + return CdiUtil + .createCdiUtil() + .findBean(PersonRepository.class) + .findByUuid(id.key.toString()) + .orElseThrow( + () -> new IllegalArgumentException( + String.format( + "No Person with uuid %s found in the database.", + id.key.toString() + ) + ) + ); + } + + @Override + public ObjectIdResolver newForDeserialization(final Object context) { + return new PersonIdResolver(); + } + + @Override + public boolean canUseFor(final ObjectIdResolver resolverType) { + return resolverType instanceof PersonIdResolver; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/assets/PersonRepository.java b/ccm-cms/src/main/java/org/librecms/assets/PersonRepository.java index cc8be29e8..33732545c 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/PersonRepository.java +++ b/ccm-cms/src/main/java/org/librecms/assets/PersonRepository.java @@ -22,19 +22,26 @@ import org.libreccm.core.AbstractEntityRepository; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; /** * * @author Jens Pelzetter */ @RequestScoped -public class PersonRepository extends AbstractEntityRepository{ - +public class PersonRepository extends AbstractEntityRepository { + private static final long serialVersionUID = 1L; + @Inject + private EntityManager enityManager; + @Override public Class getEntityClass() { return Person.class; @@ -47,20 +54,32 @@ public class PersonRepository extends AbstractEntityRepository{ @Override public Long getIdOfEntity(final Person entity) { - + return entity.getObjectId(); } @Override public boolean isNew(final Person entity) { - + return entity.getObjectId() == 0; } - + + public Optional findByUuid(final String uuid) { + try { + return Optional.of( + enityManager + .createNamedQuery("Person.findByUuid", Person.class) + .setParameter("uuid", uuid) + .getSingleResult() + ); + } catch (NoResultException ex) { + return Optional.empty(); + } + } + public List findBySurname(final String surname) { - Objects.requireNonNull(surname); - + return findAll() .stream() .filter( @@ -68,5 +87,5 @@ public class PersonRepository extends AbstractEntityRepository{ ) .collect(Collectors.toList()); } - + } diff --git a/ccm-cms/src/main/java/org/librecms/assets/PostalAddress.java b/ccm-cms/src/main/java/org/librecms/assets/PostalAddress.java index 672ef0ba7..49755efe1 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/PostalAddress.java +++ b/ccm-cms/src/main/java/org/librecms/assets/PostalAddress.java @@ -19,6 +19,8 @@ package org.librecms.assets; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import org.hibernate.envers.Audited; import org.librecms.contentsection.Asset; import org.librecms.ui.contentsections.assets.MvcAssetEditKit; @@ -52,6 +54,11 @@ import static org.librecms.assets.AssetConstants.ASSETS_BUNDLE; createStep = PostalAddressCreateStep.class, editStep = PostalAddressEditStep.class ) +@JsonIdentityInfo( + generator = ObjectIdGenerators.PropertyGenerator.class, + resolver = PostalAddressIdResolver.class, + property = "uuid" +) public class PostalAddress extends Asset { private static final long serialVersionUID = 1L; diff --git a/ccm-cms/src/main/java/org/librecms/assets/PostalAddressIdResolver.java b/ccm-cms/src/main/java/org/librecms/assets/PostalAddressIdResolver.java new file mode 100644 index 000000000..36188280a --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/assets/PostalAddressIdResolver.java @@ -0,0 +1,72 @@ +package org.librecms.assets; + + +import com.fasterxml.jackson.annotation.ObjectIdGenerator; +import com.fasterxml.jackson.annotation.ObjectIdResolver; +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.contentsection.AssetRepository; + +import java.io.Serializable; + +/* + * Copyright (C) 2022 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +/** + * + * @author Jens Pelzetter + */ +public class PostalAddressIdResolver implements Serializable, ObjectIdResolver { + + private static final long serialVersionUID = 1L; + + @Override + public void bindItem( + final ObjectIdGenerator.IdKey id, + final Object object + ) { + // According to the Jackson JavaDoc, this method can be used to keep + // track of objects directly in a resolver implementation. We don't need + // this here therefore this method is empty. + } + + @Override + public Object resolveId(final ObjectIdGenerator.IdKey id) { + return CdiUtil + .createCdiUtil() + .findBean(AssetRepository.class) + .findByUuidAndType(id.key.toString(), PostalAddress.class) + .orElseThrow( + () -> new IllegalArgumentException( + String.format( + "No PostalAddress with UUID %s found in the database.", + id.key.toString() + ) + ) + ); + } + + @Override + public ObjectIdResolver newForDeserialization(final Object context) { + return new PostalAddressIdResolver(); + } + + @Override + public boolean canUseFor(final ObjectIdResolver resolverType) { + return resolverType instanceof PostalAddressIdResolver; + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/categorization/Category.java b/ccm-core/src/main/java/org/libreccm/categorization/Category.java index c105d6b32..7a54f2ed3 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/Category.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/Category.java @@ -77,59 +77,48 @@ import javax.validation.constraints.NotBlank; @NamedQueries({ @NamedQuery( name = "Category.topLevelCategories", - query = "SELECT c FROM Category c WHERE c.parentCategory IS NULL") - , + query = "SELECT c FROM Category c WHERE c.parentCategory IS NULL"), @NamedQuery( name = "Category.findByName", - query = "SELECT c FROM Category c WHERE c.name = :name") - , + query = "SELECT c FROM Category c WHERE c.name = :name"), @NamedQuery( name = "Category.findByUuid", - query = "SELECT c FROM Category c WHERE c.uuid = :uuid") - , + query = "SELECT c FROM Category c WHERE c.uuid = :uuid"), @NamedQuery( name = "Category.findParentCategory", - query = "SELECT c.parentCategory FROM Category c WHERE c = :category") - , + query = "SELECT c.parentCategory FROM Category c WHERE c = :category"), @NamedQuery( name = "Category.countAssignedCategories", query = "SELECT COUNT(c) FROM Categorization c " + "WHERE c.categorizedObject = :object" - ) - , + ), @NamedQuery( name = "Category.isCategorized", query = "SELECT (CASE WHEN COUNT(c) > 0 THEN true ELSE false END) " + "FROM Categorization c " - + "WHERE c.categorizedObject = :object") - , + + "WHERE c.categorizedObject = :object"), @NamedQuery( name = "Category.countObjects", query = "SELECT COUNT(c) FROM Categorization c " - + "WHERE c.category = :category") - , + + "WHERE c.category = :category"), @NamedQuery( name = "Category.hasObjects", query = "SELECT (CASE WHEN COUNT(c) > 0 THEN true ELSE false END) " + "FROM Categorization c " - + "WHERE c.category = :category") - , + + "WHERE c.category = :category"), @NamedQuery( name = "Category.countSubCategories", query = "SELECT COUNT(c) FROM Category c " - + "WHERE c.parentCategory =:category") - , + + "WHERE c.parentCategory =:category"), @NamedQuery( name = "Category.hasSubCategories", query = "SELECT (CASE WHEN COUNT(c) > 0 THEN true ELSE false END) " + "FROM Category c " - + "WHERE c.parentCategory = :category") - , + + "WHERE c.parentCategory = :category"), @NamedQuery( name = "Category.findByNameAndParent", query = "SELECT c FROM Category c " - + "WHERE c.name = :name AND c.parentCategory = :parent") - , + + "WHERE c.name = :name AND c.parentCategory = :parent"), @NamedQuery( name = "Category.hasSubCategoryWithName", query = "SELECT (CASE WHEN COUNT(c) > 0 THEN true ELSE False END) " @@ -146,9 +135,11 @@ import javax.validation.constraints.NotBlank; ) }) @XmlRootElement(name = "category", namespace = CAT_XML_NS) -@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, - resolver = CategoryIdResolver.class, - property = "uuid") +@JsonIdentityInfo( + generator = ObjectIdGenerators.PropertyGenerator.class, + resolver = CategoryIdResolver.class, + property = "uuid" +) public class Category extends CcmObject implements Serializable, Exportable { private static final long serialVersionUID = -7250208963391878547L; @@ -469,14 +460,14 @@ public class Category extends CcmObject implements Serializable, Exportable { public String toString(final String data) { return super.toString(String.format(", uniqueId = %s, " + "name = \"%s\", " -// + "title = %s, " + // + "title = %s, " + "enabled = %b, " + "visible = %b, " + "abstractCategory = %s, " + "categoryOrder = %d%s", uniqueId, name, -// Objects.toString(title), + // Objects.toString(title), enabled, visible, abstractCategory,