HHH-15910 Add static remove methods to Hibernate.class
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
e0f55e5d53
commit
d8bf649998
|
@ -233,6 +233,57 @@ public final class Hibernate {
|
||||||
: list.get(key);
|
: list.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the value associated with the given key by the given persistent
|
||||||
|
* map, without fetching the state of the map from the database.
|
||||||
|
*
|
||||||
|
* @param map a persistent map associated with an open session
|
||||||
|
* @param key a key belonging to the map
|
||||||
|
* @return the previous value associated by the map with the given key, or null if there was no value associated
|
||||||
|
* with the given key
|
||||||
|
*
|
||||||
|
* @since 6.2.0
|
||||||
|
*/
|
||||||
|
public static <K, V> V remove(Map<? super K, V> map, K key) {
|
||||||
|
return ( map instanceof PersistentMap )
|
||||||
|
? ( (PersistentMap<K, V>) map ).queuedRemove( key )
|
||||||
|
: map.remove( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the specified element of the given persistent set,
|
||||||
|
* without fetching the state of the set from the database.
|
||||||
|
*
|
||||||
|
* @param set a persistent set associated with an open session
|
||||||
|
* @param element an element belonging to the set
|
||||||
|
* @return true if this set contained the specified element
|
||||||
|
*
|
||||||
|
* @since 6.2.0
|
||||||
|
*/
|
||||||
|
public static <T> boolean remove(Set<T> set, T element) {
|
||||||
|
return ( set instanceof PersistentSet )
|
||||||
|
? ( (PersistentSet<T>) set ).queuedRemove( element )
|
||||||
|
: set.remove( element );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the specified element of the given persistent list,
|
||||||
|
* without fetching the state of the list from the database.
|
||||||
|
*
|
||||||
|
* @param list a persistent list associated with an open session
|
||||||
|
* @param element an element belonging to the list
|
||||||
|
* @return true if this list contained the specified element
|
||||||
|
*
|
||||||
|
* @since 6.2.0
|
||||||
|
*/
|
||||||
|
public static <T> boolean remove(List<T> list, T element) {
|
||||||
|
return ( list instanceof PersistentList )
|
||||||
|
? ( (PersistentList<T>) list ).queuedRemove( element )
|
||||||
|
: ( list instanceof PersistentBag )
|
||||||
|
? ( (PersistentBag<T>) list ).queuedRemove( element )
|
||||||
|
: list.remove( element );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the true, underlying class of a proxied entity. This operation will
|
* Get the true, underlying class of a proxied entity. This operation will
|
||||||
* initialize a proxy by side effect.
|
* initialize a proxy by side effect.
|
||||||
|
|
|
@ -32,7 +32,8 @@ import java.util.Map;
|
||||||
* <li>Use static methods of {@link org.hibernate.Hibernate},
|
* <li>Use static methods of {@link org.hibernate.Hibernate},
|
||||||
* for example {@link org.hibernate.Hibernate#size(Collection)},
|
* for example {@link org.hibernate.Hibernate#size(Collection)},
|
||||||
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
|
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
|
||||||
* or {@link org.hibernate.Hibernate#get(Map, Object)} instead
|
* {@link org.hibernate.Hibernate#get(Map, Object)}, or
|
||||||
|
* {@link org.hibernate.Hibernate#remove(Map, Object)} instead
|
||||||
* of {@code LazyCollection(EXTRA)}.
|
* of {@code LazyCollection(EXTRA)}.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,7 +26,8 @@ import java.util.Map;
|
||||||
* <li>Use static methods of {@link org.hibernate.Hibernate},
|
* <li>Use static methods of {@link org.hibernate.Hibernate},
|
||||||
* for example {@link org.hibernate.Hibernate#size(Collection)},
|
* for example {@link org.hibernate.Hibernate#size(Collection)},
|
||||||
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
|
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
|
||||||
* or {@link org.hibernate.Hibernate#get(Map, Object)} instead
|
* {@link org.hibernate.Hibernate#get(Map, Object)}, or
|
||||||
|
* {@link org.hibernate.Hibernate#remove(Map, Object)} instead
|
||||||
* of {@code LazyCollection(EXTRA)}.
|
* of {@code LazyCollection(EXTRA)}.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -616,7 +616,7 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void throwLazyInitializationExceptionIfNotConnected() {
|
void throwLazyInitializationExceptionIfNotConnected() {
|
||||||
if ( !isConnectedToSession() ) {
|
if ( !isConnectedToSession() ) {
|
||||||
throwLazyInitializationException( "no session or session was closed" );
|
throwLazyInitializationException( "no session or session was closed" );
|
||||||
}
|
}
|
||||||
|
@ -625,7 +625,7 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void throwLazyInitializationException(String message) {
|
void throwLazyInitializationException(String message) {
|
||||||
throw new LazyInitializationException(
|
throw new LazyInitializationException(
|
||||||
"failed to lazily initialize a collection" +
|
"failed to lazily initialize a collection" +
|
||||||
(role == null ? "" : " of role: " + role) +
|
(role == null ? "" : " of role: " + role) +
|
||||||
|
|
|
@ -18,6 +18,8 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.Internal;
|
||||||
|
import org.hibernate.engine.spi.CollectionEntry;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
|
@ -404,6 +406,27 @@ public class PersistentBag<E> extends AbstractPersistentCollection<E> implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public boolean queuedRemove(Object element) {
|
||||||
|
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentBag.this );
|
||||||
|
if ( entry == null ) {
|
||||||
|
throwLazyInitializationExceptionIfNotConnected();
|
||||||
|
throwLazyInitializationException("collection not associated with session");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final CollectionPersister persister = entry.getLoadedPersister();
|
||||||
|
if ( hasQueuedOperations() ) {
|
||||||
|
getSession().flush();
|
||||||
|
}
|
||||||
|
if ( persister.elementExists( entry.getLoadedKey(), element, getSession() ) ) {
|
||||||
|
elementRemoved = true;
|
||||||
|
queueOperation( new PersistentBag.SimpleRemove( (E) element ) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsAll(Collection<?> c) {
|
public boolean containsAll(Collection<?> c) {
|
||||||
read();
|
read();
|
||||||
|
@ -633,4 +656,16 @@ public class PersistentBag<E> extends AbstractPersistentCollection<E> implements
|
||||||
bag.add( getAddedInstance() );
|
bag.add( getAddedInstance() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class SimpleRemove extends AbstractValueDelayedOperation {
|
||||||
|
|
||||||
|
public SimpleRemove(E orphan) {
|
||||||
|
super( null, orphan );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void operate() {
|
||||||
|
bag.remove( getOrphan() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ import java.util.ListIterator;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.Internal;
|
||||||
|
import org.hibernate.engine.spi.CollectionEntry;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
|
@ -217,6 +219,27 @@ public class PersistentList<E> extends AbstractPersistentCollection<E> implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public boolean queuedRemove(Object element) {
|
||||||
|
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentList.this );
|
||||||
|
if ( entry == null ) {
|
||||||
|
throwLazyInitializationExceptionIfNotConnected();
|
||||||
|
throwLazyInitializationException("collection not associated with session");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final CollectionPersister persister = entry.getLoadedPersister();
|
||||||
|
if ( hasQueuedOperations() ) {
|
||||||
|
getSession().flush();
|
||||||
|
}
|
||||||
|
if ( persister.elementExists( entry.getLoadedKey(), element, getSession() ) ) {
|
||||||
|
elementRemoved = true;
|
||||||
|
queueOperation( new PersistentList.SimpleRemove( (E) element ) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsAll(Collection<?> coll) {
|
public boolean containsAll(Collection<?> coll) {
|
||||||
read();
|
read();
|
||||||
|
|
|
@ -15,8 +15,11 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.Internal;
|
||||||
|
import org.hibernate.engine.spi.CollectionEntry;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
|
@ -192,6 +195,28 @@ public class PersistentMap<K,E> extends AbstractPersistentCollection<E> implemen
|
||||||
return map.remove( key );
|
return map.remove( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public E queuedRemove(Object key) {
|
||||||
|
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentMap.this );
|
||||||
|
if ( entry == null ) {
|
||||||
|
throwLazyInitializationExceptionIfNotConnected();
|
||||||
|
throwLazyInitializationException("collection not associated with session");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final CollectionPersister persister = entry.getLoadedPersister();
|
||||||
|
if ( hasQueuedOperations() ) {
|
||||||
|
getSession().flush();
|
||||||
|
}
|
||||||
|
Object element = persister.getElementByIndex( entry.getLoadedKey(), key, getSession(), getOwner() );
|
||||||
|
if ( element != null ) {
|
||||||
|
elementRemoved = true;
|
||||||
|
queueOperation( new Remove( (K) key, (E) element ) );
|
||||||
|
return (E) element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putAll(Map<? extends K,? extends E> puts) {
|
public void putAll(Map<? extends K,? extends E> puts) {
|
||||||
if ( puts.size() > 0 ) {
|
if ( puts.size() > 0 ) {
|
||||||
|
|
|
@ -16,6 +16,8 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.Internal;
|
||||||
|
import org.hibernate.engine.spi.CollectionEntry;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
|
@ -223,6 +225,27 @@ public class PersistentSet<E> extends AbstractPersistentCollection<E> implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public boolean queuedRemove(Object element) {
|
||||||
|
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentSet.this );
|
||||||
|
if ( entry == null ) {
|
||||||
|
throwLazyInitializationExceptionIfNotConnected();
|
||||||
|
throwLazyInitializationException("collection not associated with session");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final CollectionPersister persister = entry.getLoadedPersister();
|
||||||
|
if ( hasQueuedOperations() ) {
|
||||||
|
getSession().flush();
|
||||||
|
}
|
||||||
|
if ( persister.elementExists( entry.getLoadedKey(), element, getSession() ) ) {
|
||||||
|
elementRemoved = true;
|
||||||
|
queueOperation( new SimpleRemove( (E) element ) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsAll(Collection<?> coll) {
|
public boolean containsAll(Collection<?> coll) {
|
||||||
read();
|
read();
|
||||||
|
|
|
@ -12,7 +12,9 @@ import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -35,12 +37,16 @@ public class CollectionSizeTest {
|
||||||
emailAddresses.add( new EmailAddress( "test1@test.com" ) );
|
emailAddresses.add( new EmailAddress( "test1@test.com" ) );
|
||||||
emailAddresses.add( new EmailAddress( "test2@test.com" ) );
|
emailAddresses.add( new EmailAddress( "test2@test.com" ) );
|
||||||
emailAddresses.add( new EmailAddress( "test3@test.com" ) );
|
emailAddresses.add( new EmailAddress( "test3@test.com" ) );
|
||||||
|
List<EmailAddress> emailAddresses3 = new ArrayList<>();
|
||||||
|
emailAddresses3.add( new EmailAddress( "test4@test.com" ) );
|
||||||
|
emailAddresses3.add( new EmailAddress( "test5@test.com" ) );
|
||||||
User user = new User();
|
User user = new User();
|
||||||
user.setName( "john" );
|
user.setName( "john" );
|
||||||
Contact contact = new Contact();
|
Contact contact = new Contact();
|
||||||
contact.setName( "John Doe" );
|
contact.setName( "John Doe" );
|
||||||
contact.setEmailAddresses( emailAddresses );
|
contact.setEmailAddresses( emailAddresses );
|
||||||
emailAddresses.forEach( address -> contact.getContactsByEmail().put(address, contact) );
|
emailAddresses.forEach( address -> contact.getContactsByEmail().put(address, contact) );
|
||||||
|
contact.setEmailAddresses3( emailAddresses3 );
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
|
@ -53,15 +59,31 @@ public class CollectionSizeTest {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Contact cont = session.get(Contact.class, contact.getId());
|
Contact cont = session.get(Contact.class, contact.getId());
|
||||||
|
|
||||||
Set<EmailAddress> addresses = cont.getEmailAddresses();
|
Set<EmailAddress> addresses = cont.getEmailAddresses();
|
||||||
assertEquals( Hibernate.size(addresses), 3 );
|
assertEquals( Hibernate.size(addresses), 3 );
|
||||||
assertTrue( Hibernate.contains( addresses, new EmailAddress( "test1@test.com" ) ) );
|
assertTrue( Hibernate.contains( addresses, new EmailAddress( "test1@test.com" ) ) );
|
||||||
assertFalse( Hibernate.contains( addresses, new EmailAddress( "test9@test.com" ) ) );
|
assertFalse( Hibernate.contains( addresses, new EmailAddress( "test9@test.com" ) ) );
|
||||||
assertFalse( Hibernate.isInitialized(addresses) );
|
assertFalse( Hibernate.isInitialized(addresses) );
|
||||||
|
|
||||||
Map<EmailAddress, Contact> contactsByEmail = cont.getContactsByEmail();
|
Map<EmailAddress, Contact> contactsByEmail = cont.getContactsByEmail();
|
||||||
assertEquals( cont, Hibernate.get(contactsByEmail, new EmailAddress( "test1@test.com" ) ) );
|
assertEquals( cont, Hibernate.get(contactsByEmail, new EmailAddress( "test1@test.com" ) ) );
|
||||||
assertNull( Hibernate.get(contactsByEmail, new EmailAddress( "test9@test.com" ) ) );
|
assertNull( Hibernate.get(contactsByEmail, new EmailAddress( "test9@test.com" ) ) );
|
||||||
assertFalse( Hibernate.isInitialized(contactsByEmail) );
|
assertFalse( Hibernate.isInitialized(contactsByEmail) );
|
||||||
|
|
||||||
|
Hibernate.remove( contactsByEmail, new EmailAddress( "test1@test.com" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized(contactsByEmail) );
|
||||||
|
assertEquals( cont, Hibernate.get(contactsByEmail, new EmailAddress( "test1@test.com" ) ) );
|
||||||
|
assertEquals( Hibernate.size( contactsByEmail.entrySet() ), 3 );
|
||||||
|
|
||||||
|
Hibernate.remove( addresses, new EmailAddress( "test1@test.com" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized(addresses) );
|
||||||
|
assertEquals( Hibernate.size( addresses ), 3 );
|
||||||
|
|
||||||
|
List<EmailAddress> addresses3 = cont.getEmailAddresses3();
|
||||||
|
Hibernate.remove( addresses3, new EmailAddress( "test4@test.com" ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( addresses3 ) );
|
||||||
|
assertEquals( Hibernate.size(addresses3), 2 );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
package org.hibernate.orm.test.collection.basic;
|
package org.hibernate.orm.test.collection.basic;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
|
@ -31,6 +33,8 @@ public class Contact implements Serializable {
|
||||||
private String name;
|
private String name;
|
||||||
private Set<EmailAddress> emailAddresses = new HashSet<>();
|
private Set<EmailAddress> emailAddresses = new HashSet<>();
|
||||||
private Set<EmailAddress> emailAddresses2 = new HashSet<>();
|
private Set<EmailAddress> emailAddresses2 = new HashSet<>();
|
||||||
|
|
||||||
|
private List<EmailAddress> emailAddresses3 = new ArrayList<>();
|
||||||
private Map<EmailAddress,Contact> contactsByEmail = new HashMap<>();
|
private Map<EmailAddress,Contact> contactsByEmail = new HashMap<>();
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -52,6 +56,16 @@ public class Contact implements Serializable {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@CollectionTable(name = "user_email_addresses3", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
|
||||||
|
public List<EmailAddress> getEmailAddresses3() {
|
||||||
|
return emailAddresses3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmailAddresses3(List<EmailAddress> emailAddresses3) {
|
||||||
|
this.emailAddresses3 = emailAddresses3;
|
||||||
|
}
|
||||||
|
|
||||||
@ElementCollection
|
@ElementCollection
|
||||||
@CollectionTable(name = "user_email_addresses2", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
|
@CollectionTable(name = "user_email_addresses2", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
|
||||||
public Set<EmailAddress> getEmailAddresses2() {
|
public Set<EmailAddress> getEmailAddresses2() {
|
||||||
|
|
Loading…
Reference in New Issue