Сегодня я столкнулся с этой проблемой, и я думаю, что Thymeleaf не предлагает для этого легкого решения. Вы всегда можете установить ссылки на родителя на null
перед тем, как передать его Тимелеафу, но это кажется уродливым.
Исследуя исходный код Тимелеафа, я заметил, что он использует Introspector для получения информации о свойствах, поэтому мы можем скрыть некоторые свойства, реализовав BeanInfo
. Самый простой способ сделать это - создать класс в одном пакете вашего компонента, добавив BeanInfo
к имени. Вы можете расширить SimpleBeanInfo
и реализовать только те методы, которые вас интересуют (в данном случае getPropertyDescriptors
).
В вашем примере, вы могли бы сделать:
public class InventoryItemBeanInfo extends SimpleBeanInfo {
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
try {
PropertyDescriptor id = new PropertyDescriptor("id", InventoryItem.class);
PropertyDescriptor[] descriptors = {id};
return descriptors;
} catch (IntrospectionException e) {
throw new Error(e.toString());
}
}
}
Таким образом, Thymeleaf не будет видеть ваше Player
собственность, и вы не имели бы бесконечную рекурсию больше.
Недостатком этого решения является то, что вы должны помнить, что каждый раз, когда вы изменяете атрибуты своего компонента InventoryItem
, вам нужно перейти к BeanInfo
и добавить к нему новый атрибут.
Итак, я придумал другое решение. Это немного сложнее, но как только он настроен, его легче поддерживать.
Начнем с создания аннотации, указывающей, что свойство должно быть скрыто. Давайте назовем это HiddenProperty
:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HiddenProperty {}
Сейчас мы реализуем общий BeanInfo
класс, который будет инспектировать боб с помощью отражения и найти свойства.Мы также будем проверять существование наших аннотаций и когда он присутствует в пренебрежении метод:
public class HiddenPropertyAwareBeanInfo extends SimpleBeanInfo {
private Class<?> beanClass;
private PropertyDescriptor[] descriptors;
public HiddenPropertyAwareBeanInfo(Class<?> beanClass) {
this.beanClass = beanClass;
}
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
if(descriptors != null) {
return descriptors;
}
Method[] methodList = beanClass.getMethods();
List<PropertyDescriptor> propDescriptors = new ArrayList<>();
for(Method m : methodList) {
if(Modifier.isStatic(m.getModifiers())) {
continue;
}
try {
if(m.getParameterCount() == 0 && !m.isAnnotationPresent(HiddenProperty.class)) {
if(m.getName().startsWith("get")) {
propDescriptors.add(new PropertyDescriptor(m.getName().substring(3), beanClass));
} else if(m.getName().startsWith("is")) {
propDescriptors.add(new PropertyDescriptor(m.getName().substring(2), beanClass));
}
}
} catch(IntrospectionException ex) {
continue;
}
}
descriptors = new PropertyDescriptor[propDescriptors.size()];
return propDescriptors.toArray(descriptors);
}
}
Теперь создайте BeanInfo
, который расширяет этот класс:
public class InventoryItemBeanInfo extends HiddenPropertyAwareBeanInfo {
public InventoryItemBeanInfo() {
super(InventoryItem.class);
}
}
Наконец, аннотировать методы получения из недвижимость, которую вы хотите скрыть:
@Entity
@Table(name = "inventory_item")
public class InventoryItem {
@Id
@GeneratedValue
@Column(name = "id")
private int id;
@ManyToOne
@JoinColumn(name="id_player")
private Player player;
public InventoryItem() {
}
@HiddenProperty
public Player getPlayer() {
return this.player;
}
//Other getters and setters...
}
И у вас оно есть. Теперь вы можете изменить свои свойства столько, сколько хотите, и ваше имущество Player
не будет видно Thymeleaf.
Важно отметить, что это решение не соответствует 100% спецификации Java Beans, оно не учитывает наличие индексированных свойств и некоторых других деталей. Вы можете посмотреть Introspector
source code, чтобы узнать, как они извлекают эту информацию и улучшают это решение.
Но, лично, я думаю, что это должно быть исправлено внутри Тимелеафа. Тимелеаф - невероятно элегантный инструмент, и прибегать к такого рода обходным решениям делает меня грустным.
Я использовал ваше первое предложение и установил ссылку на родителя равным нулю, и это сработало – gary69