jmix 2.8.2
В нашем проекте есть многомодульное fullstack приложение (типа такого mariodavid/jmix-insurance: Jmix Sample Multi Module Example of the Insurance Domain) и дополнительно клиентское приложение на REST DataStore. Модули основного приложения опциональны, то есть при развертывании мы можем не включать какие-то модули и их не будет в приложении.
Один из модулей переопределяет сущности других модулей через @ReplaceEntity.
Например была сущность:
@JmixEntity
@Entity(name = "OriginalEntity")
public class OriginalEntity {
...
}
А стала:
@JmixEntity
@Entity(name = "ReplacedEntity")
@ReplaceEntity(OriginalEntity.class)
public class ReplacedEntity extends OriginalEntity {
...
}
В клиентском приложении REST DataStore создано dto для OriginalEntity :
@JmixEntity(name = "OriginalEntity")
@Store(name = "...")
public class OriginalEntity {
...
}
Никаких атрибутов из ReplacedEntity на клиенте нет, он вообще никак не привязан к переопределенной сущности, ему интересна только оригинальная.
При такой конфигурации возникает ошибка на клиенте, при запросе сущности OriginalEntity:
java.lang.IllegalArgumentException: MetaClass not found for ReplacedEntity
Насколько я понимаю, бэкенд на запрос OriginalEntity возвращает ReplacedEntity, а клиент не может у себя найти такой мета класс.
Также пробовал
@JmixEntity
@RestDataStoreEntity(remoteName= "OriginalEntity")
@Store(name = "...")
public class OriginalEntity {
...
}
И
@JmixEntity(name = "OriginalEntity")
@RestDataStoreEntity(remoteName= "OriginalEntity")
@Store(name = "...")
public class OriginalEntity {
...
}
Не работает.
Работает только вариант если на клиенте указать название переопределенной сущности:
@JmixEntity(name = "ReplacedEntity")
@Store(name = "...")
public class OriginalEntity {
...
}
Но такой вариант нам не подходит, потому что модуль с ReplacedEntity опциональный, то есть в каких-то развертываниях будет ReplacedEntity, а в каких-то будет OriginalEntity.
Также это просто не удобно и не надежно при каждом переопределении на бэке проверять/исправлять сущности на клиенте.
Пока что пришел к такому воркэраунду:
- На бэке сделал RestMethod, который принимает список мета классов (имен) и возвращает названия соответствующих переопределенных сущностей.
@RestService("ReplacedEntitiesService")
public class ReplacedEntitiesService {
private final Metadata metadata;
public ReplacedEntitiesService(Metadata metadata) {
this.metadata = metadata;
}
@RestMethod
public Map<String, String> getReplacedEntityNames(Collection<String> entityNames) {
Map<String, String> replacedEntityNames = new HashMap<>();
for (var name : entityNames) {
String metaClassName = metadata.getClass(name).getName();
if (Objects.equals(metaClassName, name)) continue;
replacedEntityNames.put(name, metaClassName);
}
return replacedEntityNames;
}
}
- Клиент вызывает этот метод и сохраняет к себе в Session актуальные названия сущностей, полученные с бэка
Session session = metadata.getSession();
if (session instanceof SessionImplementation sessionImplementation) {
List<String> localEntityNames = metadata.getClasses().stream().map(MetadataObject::getName).toList();
Map<String, String> replacedEntityNames = replacedEntitiesService.getReplacedEntityNames(localEntityNames);
for (var localName : replacedEntityNames.keySet()) {
String replacedName = replacedEntityNames.get(localName);
MetaClass localMetaClass = metadata.getClass(localName);
sessionImplementation.registerClass(replacedName, localMetaClass.getJavaClass(), localMetaClass);
}
} else {
LOG.warn("Session expected to be an instance of '{}', but is '{}'",
SessionImplementation.class, session.getClass());
}