/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.ee;
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.security.Permission;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.time.Period;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology;
import java.time.chrono.Era;
import java.time.format.DateTimeFormatter;
import java.time.format.DecimalStyle;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.ValueRange;
import java.time.temporal.WeekFields;
import java.time.zone.ZoneOffsetTransition;
import java.time.zone.ZoneOffsetTransitionRule;
import java.time.zone.ZoneRules;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Currency;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.function.Predicate;
/**
* Determines whether a given object is immutable.
* @author Paul Ferraro
*/
public enum Immutability implements Predicate<Object> {
OBJECT() {
// Singleton immutable objects detectable via reference equality test
private final Set<Object> immutableObjects = createIdentitySet(Arrays.asList(
null,
Collections.emptyEnumeration(),
Collections.emptyIterator(),
Collections.emptyList(),
Collections.emptyListIterator(),
Collections.emptyMap(),
Collections.emptyNavigableMap(),
Collections.emptyNavigableSet(),
Collections.emptySet(),
Collections.emptySortedMap(),
Collections.emptySortedSet()
));
@Override
public boolean test(Object object) {
return this.immutableObjects.contains(object);
}
},
CLASS() {
// Concrete immutable classes detectable via reference equality test
private final Set<Class<?>> immutableClasses = createIdentitySet(Arrays.asList(
BigDecimal.class,
BigInteger.class,
Boolean.class,
Byte.class,
Character.class,
Class.class,
Currency.class,
DateTimeFormatter.class,
DecimalStyle.class,
Double.class,
Duration.class,
File.class,
Float.class,
Inet4Address.class,
Inet6Address.class,
InetSocketAddress.class,
Instant.class,
Integer.class,
Locale.class,
LocalDate.class,
LocalDateTime.class,
LocalTime.class,
Long.class,
MathContext.class,
MonthDay.class,
Period.class,
Short.class,
StackTraceElement.class,
String.class,
URI.class,
URL.class,
UUID.class,
ValueRange.class,
WeekFields.class,
Year.class,
YearMonth.class,
ZoneOffset.class,
ZoneOffsetTransition.class,
ZoneOffsetTransitionRule.class,
ZoneRules.class,
ZonedDateTime.class
));
@Override
public boolean test(Object object) {
return this.immutableClasses.contains(object.getClass());
}
},
ABSTRACT_CLASS() {
// Interfaces and abstract classes documented to be immutable, but only detectable via instanceof tests
private final List<Class<?>> immutableClasses = Arrays.asList(
Chronology.class,
ChronoLocalDate.class,
Clock.class,
Enum.class, // In theory, one could implement a mutable enum, but that would just be weird.
Era.class,
Path.class,
Permission.class,
TemporalField.class,
TemporalUnit.class,
TimeZone.class, // Strictly speaking, this class is mutable, although in practice it is never mutated.
ZoneId.class
);
@Override
public boolean test(Object object) {
return this.immutableClasses.stream().anyMatch(immutableClass -> immutableClass.isInstance(object));
}
},
COLLECTION() {
@Override
public boolean test(Object object) {
return COLLECTION_INSTANCE.test(object);
}
},
ANNOTATION() {
@Override
public boolean test(Object object) {
return object.getClass().isAnnotationPresent(net.jcip.annotations.Immutable.class);
}
},
;
public static final Predicate<Object> INSTANCE = object -> EnumSet.allOf(Immutability.class).stream().anyMatch(predicate -> predicate.test(object));
static final Predicate<Object> COLLECTION_INSTANCE = new CollectionImmutability(INSTANCE);
static <T> Set<T> createIdentitySet(Collection<T> list) {
Set<T> result = Collections.newSetFromMap(new IdentityHashMap<>(list.size()));
result.addAll(list);
return Collections.unmodifiableSet(result);
}
}