Merge remote-tracking branch 'upstream/master' into wip/6.0
This commit is contained in:
commit
aff9bb4609
|
@ -411,7 +411,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
continue;
|
||||
}
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
|
||||
if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) {
|
||||
if ( enhancementContext.isPersistentField( annotatedField ) && enhancementContext.isMappedCollection( annotatedField ) ) {
|
||||
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
|
||||
collectionList.add( annotatedField );
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ public class EnhancerImpl implements Enhancer {
|
|||
for ( FieldDescription ctField : managedCtSuperclass.getDeclaredFields() ) {
|
||||
if ( !Modifier.isStatic( ctField.getModifiers() ) ) {
|
||||
AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription( enhancementContext, ctField );
|
||||
if ( enhancementContext.isPersistentField( annotatedField ) && !enhancementContext.isMappedCollection( annotatedField ) ) {
|
||||
if ( enhancementContext.isPersistentField( annotatedField ) && enhancementContext.isMappedCollection( annotatedField ) ) {
|
||||
if ( ctField.getType().asErasure().isAssignableTo( Collection.class ) || ctField.getType().asErasure().isAssignableTo( Map.class ) ) {
|
||||
collectionList.add( annotatedField );
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.bytecode.enhance.spi;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -106,7 +108,13 @@ public class DefaultEnhancementContext implements EnhancementContext {
|
|||
*/
|
||||
@Override
|
||||
public boolean isMappedCollection(UnloadedField field) {
|
||||
return field.hasAnnotation( OneToMany.class ) || field.hasAnnotation( ManyToMany.class ) || field.hasAnnotation( ElementCollection.class );
|
||||
// If the collection is definitely a plural attribute, we respect that
|
||||
if (field.hasAnnotation( OneToMany.class ) || field.hasAnnotation( ManyToMany.class ) || field.hasAnnotation( ElementCollection.class )) {
|
||||
return true;
|
||||
}
|
||||
// But a collection might be treated like a singular attribute if it is annotated with `@Basic`
|
||||
// If no annotations are given though, a collection is treated like a OneToMany
|
||||
return !field.hasAnnotation( Basic.class );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.engine.spi.Status;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.UniqueKeyLoadable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
/**
|
||||
* A base implementation of EntityEntry
|
||||
|
@ -321,7 +322,24 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry {
|
|||
@SuppressWarnings( {"SimplifiableIfStatement"})
|
||||
private boolean isUnequivocallyNonDirty(Object entity) {
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
return ! persister.hasCollections() && ! ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
|
||||
boolean uninitializedProxy = false;
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) entity;
|
||||
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
|
||||
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
|
||||
EnhancementAsProxyLazinessInterceptor enhancementAsProxyLazinessInterceptor = (EnhancementAsProxyLazinessInterceptor) interceptor;
|
||||
// When a proxy has dirty attributes, we have to treat it like a normal entity to flush changes
|
||||
uninitializedProxy = !enhancementAsProxyLazinessInterceptor.isInitialized() && !( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
|
||||
}
|
||||
}
|
||||
else if ( entity instanceof HibernateProxy ) {
|
||||
uninitializedProxy = ( (HibernateProxy) entity ).getHibernateLazyInitializer()
|
||||
.isUninitialized();
|
||||
}
|
||||
// we never have to check an uninitialized proxy
|
||||
return uninitializedProxy || !persister.hasCollections()
|
||||
&& !persister.hasMutableProperties()
|
||||
&& !( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
|
||||
}
|
||||
|
||||
if ( entity instanceof PersistentAttributeInterceptable ) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.engine.internal.Nullability;
|
|||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
|
@ -39,6 +40,7 @@ import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
|
|||
import org.hibernate.metadata.ClassMetadata;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -525,18 +527,13 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
|
|||
|
||||
if ( dirtyProperties == null ) {
|
||||
if ( entity instanceof SelfDirtinessTracker ) {
|
||||
if ( ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes() ) {
|
||||
int[] dirty = persister.resolveAttributeIndexes( ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() );
|
||||
|
||||
// HHH-12051 - filter non-updatable attributes
|
||||
// TODO: add Updatability to EnhancementContext and skip dirty tracking of those attributes
|
||||
int count = 0;
|
||||
for ( int i : dirty ) {
|
||||
if ( persister.getPropertyUpdateability()[i] ) {
|
||||
dirty[count++] = i;
|
||||
}
|
||||
}
|
||||
dirtyProperties = count == 0 ? ArrayHelper.EMPTY_INT_ARRAY : count == dirty.length ? dirty : Arrays.copyOf( dirty, count );
|
||||
if ( ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes() || persister.hasMutableProperties() ) {
|
||||
dirtyProperties = persister.resolveDirtyAttributeIndexes(
|
||||
values,
|
||||
loadedState,
|
||||
( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes(),
|
||||
session
|
||||
);
|
||||
}
|
||||
else {
|
||||
dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -78,6 +79,7 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
|||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.CascadingActions;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityEntryFactory;
|
||||
|
@ -91,6 +93,7 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
|||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.ValueInclusion;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
|
@ -2449,6 +2452,52 @@ public abstract class AbstractEntityPersister
|
|||
return Arrays.copyOf( fields, counter );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] resolveDirtyAttributeIndexes(
|
||||
final Object[] currentState,
|
||||
final Object[] previousState,
|
||||
final String[] attributeNames,
|
||||
final SessionImplementor session) {
|
||||
final BitSet mutablePropertiesIndexes = entityMetamodel.getMutablePropertiesIndexes();
|
||||
final int estimatedSize = attributeNames == null ? 0 : attributeNames.length + mutablePropertiesIndexes.cardinality();
|
||||
final List<Integer> fields = new ArrayList<>( estimatedSize );
|
||||
if ( estimatedSize == 0 ) {
|
||||
return ArrayHelper.EMPTY_INT_ARRAY;
|
||||
}
|
||||
if ( !mutablePropertiesIndexes.isEmpty() ) {
|
||||
// We have to check the state for "mutable" properties as dirty tracking isn't aware of mutable types
|
||||
final Type[] propertyTypes = entityMetamodel.getPropertyTypes();
|
||||
final boolean[] propertyCheckability = entityMetamodel.getPropertyCheckability();
|
||||
mutablePropertiesIndexes.stream().forEach( i -> {
|
||||
// This is kindly borrowed from org.hibernate.type.TypeHelper.findDirty
|
||||
final boolean dirty = currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY &&
|
||||
( previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ||
|
||||
( propertyCheckability[i]
|
||||
&& propertyTypes[i].isDirty(
|
||||
previousState[i],
|
||||
currentState[i],
|
||||
propertyColumnUpdateable[i],
|
||||
session
|
||||
) ) );
|
||||
if ( dirty ) {
|
||||
fields.add( i );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
if ( attributeNames != null ) {
|
||||
final boolean[] propertyUpdateability = entityMetamodel.getPropertyUpdateability();
|
||||
for ( String attributeName : attributeNames ) {
|
||||
final Integer index = entityMetamodel.getPropertyIndexOrNull( attributeName );
|
||||
if ( index != null && propertyUpdateability[index] && !fields.contains( index ) ) {
|
||||
fields.add( index );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ArrayHelper.toIntArray( fields );
|
||||
}
|
||||
|
||||
protected String[] getSubclassPropertySubclassNameClosure() {
|
||||
return subclassPropertySubclassNameClosure;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.cache.spi.entry.CacheEntryStructure;
|
|||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.EntityEntryFactory;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.ValueInclusion;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
|
@ -884,6 +885,25 @@ public interface EntityPersister
|
|||
*/
|
||||
int[] resolveAttributeIndexes(String[] attributeNames);
|
||||
|
||||
/**
|
||||
* Like {@link #resolveAttributeIndexes(String[])} but also always returns mutable attributes
|
||||
*
|
||||
*
|
||||
* @param values
|
||||
* @param loadedState
|
||||
* @param attributeNames Array of names to be resolved
|
||||
*
|
||||
* @param session
|
||||
* @return A set of unique indexes of the attribute names found in the metamodel
|
||||
*/
|
||||
default int[] resolveDirtyAttributeIndexes(
|
||||
Object[] values,
|
||||
Object[] loadedState,
|
||||
String[] attributeNames,
|
||||
SessionImplementor session) {
|
||||
return resolveAttributeIndexes( attributeNames );
|
||||
}
|
||||
|
||||
boolean canUseReferenceCacheEntries();
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.tuple.entity;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -43,6 +44,7 @@ import org.hibernate.tuple.PropertyFactory;
|
|||
import org.hibernate.tuple.ValueGeneration;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.ManyToOneType;
|
||||
|
@ -97,7 +99,7 @@ public class EntityMetamodel implements Serializable {
|
|||
|
||||
private final Map<String, Integer> propertyIndexes = new HashMap<>();
|
||||
private final boolean hasCollections;
|
||||
private final boolean hasMutableProperties;
|
||||
private final BitSet mutablePropertiesIndexes;
|
||||
private final boolean hasLazyProperties;
|
||||
private final boolean hasNonIdentifierPropertyNamedId;
|
||||
|
||||
|
@ -206,7 +208,7 @@ public class EntityMetamodel implements Serializable {
|
|||
int tempVersionProperty = NO_VERSION_INDX;
|
||||
boolean foundCascade = false;
|
||||
boolean foundCollection = false;
|
||||
boolean foundMutable = false;
|
||||
BitSet mutableIndexes = new BitSet();
|
||||
boolean foundNonIdentifierPropertyNamedId = false;
|
||||
boolean foundUpdateableNaturalIdProperty = false;
|
||||
|
||||
|
@ -316,8 +318,9 @@ public class EntityMetamodel implements Serializable {
|
|||
foundCollection = true;
|
||||
}
|
||||
|
||||
if ( propertyTypes[i].isMutable() && propertyCheckability[i] ) {
|
||||
foundMutable = true;
|
||||
// Component types are dirty tracked as well so they are not exactly mutable for the "maybeDirty" check
|
||||
if ( propertyTypes[i].isMutable() && propertyCheckability[i] && !( propertyTypes[i] instanceof ComponentType ) ) {
|
||||
mutableIndexes.set( i );
|
||||
}
|
||||
|
||||
mapPropertyToIndex(prop, i);
|
||||
|
@ -393,7 +396,7 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
|
||||
hasCollections = foundCollection;
|
||||
hasMutableProperties = foundMutable;
|
||||
mutablePropertiesIndexes = mutableIndexes;
|
||||
|
||||
iter = persistentClass.getSubclassIterator();
|
||||
final Set<String> subclassEntityNamesLocal = new HashSet<>();
|
||||
|
@ -874,7 +877,11 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
|
||||
public boolean hasMutableProperties() {
|
||||
return hasMutableProperties;
|
||||
return !mutablePropertiesIndexes.isEmpty();
|
||||
}
|
||||
|
||||
public BitSet getMutablePropertiesIndexes() {
|
||||
return mutablePropertiesIndexes;
|
||||
}
|
||||
|
||||
public boolean hasNonIdentifierPropertyNamedId() {
|
||||
|
|
|
@ -63,11 +63,20 @@ public class DirtyTrackingTest {
|
|||
EnhancerTestUtils.checkDirtyTracking( entity, "someStrings" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
// Association: this should not set the entity to dirty
|
||||
Set<Integer> intSet = new HashSet<>();
|
||||
intSet.add( 42 );
|
||||
entity.someInts = intSet;
|
||||
// Association, 1: creating the association will mark it dirty
|
||||
Set<OtherEntity> associatedSet = new HashSet<>();
|
||||
OtherEntity o = new OtherEntity();
|
||||
o.id = 1l;
|
||||
o.name = "other";
|
||||
associatedSet.add( o );
|
||||
entity.someAssociation = associatedSet;
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "someAssociation" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
// Association, 2: modifying a related entity should not
|
||||
o.name = "newName";
|
||||
EnhancerTestUtils.checkDirtyTracking( entity );
|
||||
EnhancerTestUtils.checkDirtyTracking( o, "name" );
|
||||
|
||||
// testing composite object
|
||||
Address address = new Address();
|
||||
|
@ -125,7 +134,7 @@ public class DirtyTrackingTest {
|
|||
List<String> someStrings;
|
||||
|
||||
@OneToMany
|
||||
Set<Integer> someInts;
|
||||
Set<OtherEntity> someAssociation;
|
||||
|
||||
@Embedded
|
||||
Address address;
|
||||
|
@ -141,4 +150,11 @@ public class DirtyTrackingTest {
|
|||
this.someNumber = someNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class OtherEntity {
|
||||
@Id
|
||||
Long id;
|
||||
String name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
|
||||
package org.hibernate.test.bytecode.enhancement.mutable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.persistence.AttributeConverter;
|
||||
|
||||
public class MapStringConverter implements AttributeConverter<Map<String, String>, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(Map<String, String> attribute) {
|
||||
if ( attribute == null ) {
|
||||
return null;
|
||||
}
|
||||
return attribute.entrySet().stream()
|
||||
.map( entry -> entry.getKey() + ";" + entry.getValue() )
|
||||
.collect( Collectors.joining( ";" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> convertToEntityAttribute(String dbData) {
|
||||
if ( dbData == null ) {
|
||||
return null;
|
||||
}
|
||||
String[] strings = dbData.split( ";" );
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for ( int i = 0; i < strings.length; i += 2 ) {
|
||||
map.put( strings[i], strings[i + 1] );
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
|
||||
package org.hibernate.test.bytecode.enhancement.mutable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
public class MutableTypeEnhancementTestCase extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { TestEntity.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14329")
|
||||
public void testMutateMutableTypeObject() throws Exception {
|
||||
inTransaction( entityManager -> {
|
||||
TestEntity e = new TestEntity();
|
||||
e.setId( 1L );
|
||||
e.setDate( new Date() );
|
||||
e.getTexts().put( "a", "abc" );
|
||||
entityManager.persist( e );
|
||||
} );
|
||||
|
||||
inTransaction( entityManager -> {
|
||||
TestEntity e = entityManager.find( TestEntity.class, 1L );
|
||||
e.getDate().setTime( 0 );
|
||||
e.getTexts().put( "a", "def" );
|
||||
} );
|
||||
|
||||
inTransaction( entityManager -> {
|
||||
TestEntity e = entityManager.find( TestEntity.class, 1L );
|
||||
Assert.assertEquals( 0L, e.getDate().getTime() );
|
||||
Assert.assertEquals( "def", e.getTexts().get( "a" ) );
|
||||
} );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.mutable;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
@Entity
|
||||
public class TestEntity {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date date;
|
||||
|
||||
@Basic
|
||||
@Column(name = "TEXTS")
|
||||
@Convert(converter = MapStringConverter.class)
|
||||
private Map<String, String> texts = new HashMap<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Map<String, String> getTexts() {
|
||||
return texts;
|
||||
}
|
||||
|
||||
public void setTexts(Map<String, String> texts) {
|
||||
this.texts = texts;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue