47

In my code, I am creating a collection of objects which will be accessed by various threads in a fashion that is only safe if the objects are immutable. When an attempt is made to insert a new object into my collection, I want to test to see if it is immutable (if not, I'll throw an exception).

One thing I can do is to check a few well-known immutable types:

private static final Set<Class> knownImmutables = new HashSet<Class>(Arrays.asList(
        String.class, Byte.class, Short.class, Integer.class, Long.class,
        Float.class, Double.class, Boolean.class, BigInteger.class, BigDecimal.class
));

...

public static boolean isImmutable(Object o) {
    return knownImmutables.contains(o.getClass());
}

This actually gets me 90% of the way, but sometimes my users will want to create simple immutable types of their own:

public class ImmutableRectangle {
    private final int width;
    private final int height;
    public ImmutableRectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
}

Is there some way (perhaps using reflection) that I could reliably detect whether a class is immutable? False positives (thinking it's immutable when it isn't) are not acceptable but false negatives (thinking it's mutable when it isn't) are.

Edited to add: Thanks for the insightful and helpful answers. As some of the answers pointed out, I neglected to define my security objectives. The threat here is clueless developers -- this is a piece of framework code that will be used by large numbers of people who know next-to-nothing about threading and won't be reading the documentation. I do NOT need to defend against malicious developers -- anyone clever enough to mutate a String or perform other shenanigans will also be smart enough to know it's not safe in this case. Static analysis of the codebase IS an option, so long as it is automated, but code reviews cannot be counted on because there is no guarantee every review will have threading-savvy reviewers.

mcherm
  • 23,999
  • 10
  • 44
  • 50
  • There are ways to reliably detect immutability in Java. It's a huge subject, though, on how to go about figuring that out. I have provided an Answer to another very similar question addressing how you might go about thoroughly approaching this problem space. https://stackoverflow.com/a/75043881/501113 – chaotic3quilibrium Jan 07 '23 at 21:47

14 Answers14

31

There is no reliable way to detect if a class is immutable. This is because there are so many ways a property of a class might be altered and you can't detect all of them via reflection.

The only way to get close to this is:

  • Only allow final properties of types that are immutable (primitive types and classes you know are immutable),
  • Require the class to be final itself
  • Require that they inherit from a base class you provide (which is guaranteed to be immutable)

Then you can check with the following code if the object you have is immutable:

static boolean isImmutable(Object obj) {
    Class<?> objClass = obj.getClass();

    // Class of the object must be a direct child class of the required class
    Class<?> superClass = objClass.getSuperclass();
    if (!Immutable.class.equals(superClass)) {
        return false;
    }

    // Class must be final
    if (!Modifier.isFinal(objClass.getModifiers())) {
        return false;
    }

    // Check all fields defined in the class for type and if they are final
    Field[] objFields = objClass.getDeclaredFields();
    for (int i = 0; i < objFields.length; i++) {
        if (!Modifier.isFinal(objFields[i].getModifiers())
                || !isValidFieldType(objFields[i].getType())) {
            return false;
        }
    }

    // Lets hope we didn't forget something
    return true;
}

static boolean isValidFieldType(Class<?> type) {
    // Check for all allowed property types...
    return type.isPrimitive() || String.class.equals(type);
}

Update: As suggested in the comments, it could be extended to recurse on the superclass instead of checking for a certain class. It was also suggested to recursively use isImmutable in the isValidFieldType Method. This could probably work and I have also done some testing. But this is not trivial. You can't just check all field types with a call to isImmutable, because String already fails this test (its field hash is not final!). Also you are easily running into endless recursions, causing StackOverflowErrors ;) Other problems might be caused by generics, where you also have to check their types for immutablity.

I think with some work, these potential problems might be solved somehow. But then, you have to ask yourself first if it really is worth it (also performance wise).

Simon Lehmann
  • 10,737
  • 4
  • 41
  • 53
  • Maybe "isValidFieldType" could do a recursion to isImmutable. :-) – marcospereira Oct 15 '08 at 03:37
  • With marcospereira's modification, this could be quite useful! We could also recurse on the superclass (allowing Object as a special case) which would eliminate the need to inherit from a common ancestor. This is good! – mcherm Oct 15 '08 at 13:14
  • These are good suggestions. I tried to avoid recursing on the superclasses and members for the sake of simplicity and performance (the recursion could get quite extensive). But I'll add these suggestions to the anweser. – Simon Lehmann Oct 15 '08 at 16:01
  • If you're checking the class of a specific instance, there is IMHO no need for it to be final - if another instance comes by that is a subclass, it will be checked anyways. – Martin Probst Oct 20 '08 at 12:18
  • "There is no reliable way to detect if a class is immutable." - this is not the case. Perhaps you mean using just reflection? But bytecode analysis using a library such as BCEL or ASM would allow discovering if a class is mutable. In fact, I've just done 95% of that as part of a university assignment. – Grundlefleck Dec 10 '09 at 17:11
  • @Grundlefleck: Could you explain how to do this using bytecode analysis? Can this be done easily during runtime? I find this really interesting and it would probably help others who want to do this in the future. – Simon Lehmann Dec 11 '09 at 10:23
  • @Simon, there are several checks which could ensure a class is immutable - if the fields are immutable and and can't be reassigned, etc. The tool I created checked these things with ASM. It was static, but I don't know of any reason why it wouldn't work at run time. If you're interested in hearing more, you can contact me at grundlefleck at gmail dot com. The tool is basic, written in two weeks, but if you're interested, I can see if I can get it thrown up on googlecode or something. – Grundlefleck Dec 16 '09 at 19:49
  • why do think making attribute primitive helps immutability. I can modify it using reflection. – plzdontkillme Jul 03 '14 at 17:08
  • Anything can be modified with reflection. I immutability assumes regular program that obeys the java access modifiers – Sgene9 Oct 10 '17 at 13:11
31

Use the Immutable annotation from Java Concurrency in Practice. The tool FindBugs can then help in detecting classes which are mutable but shouldn't be.

beresfordt
  • 5,088
  • 10
  • 35
  • 43
Benno Richters
  • 15,378
  • 14
  • 42
  • 45
  • How should he apply FindBugs while running his code? From what I understand he wants to check at runtime if a mutable object is added? – Daniel Hiller Oct 15 '08 at 10:45
  • He can use Findbugs at build time to reduce the number of missanotated classes and use the annotation at runtime. – ddimitrov Oct 15 '08 at 13:18
  • 6
    I hadn't realized that Findbugs did this analysis -- that's great! I took a look at the docs and it seems that it simply verifies that all fields of an annotated class are final (but does not verify that they all contain immutable objects). – mcherm Oct 15 '08 at 13:43
  • You can also enable IntelliJ to check your code against these annotations: [Tweet from Brian Goetz](https://twitter.com/briangoetz/status/8577345828). Here are the annotations as a Maven dependency: [link](http://mvnrepository.com/artifact/net.jcip/jcip-annotations/1.0) – Matthias Braun Dec 07 '15 at 16:26
9

At my company we've defined an Attribute called @Immutable. If you choose to attach that to a class, it means you promise you're immutable.

It works for documentation, and in your case it would work as a filter.

Of course you're still depending on the author keeping his word about being immutable, but since the author explicitly added the annotation it's a reasonable assumption.

Jason Cohen
  • 81,399
  • 26
  • 107
  • 114
  • If you're depending on the author keeping his word that it's immutable what's the point? It's not adding anything, and it could potentially cause harm if people think the annotation *makes* their class immutable.. – SCdF Oct 15 '08 at 02:26
  • The idea is hopefully in the near future you'll have some static code analysis - maybe integrated into your IDE - to go through your code and check that your @Immutable annotated classes *are* actually immutable. – Cem Catikkas Oct 15 '08 at 02:56
  • At Jason's company (which I also work at), we also code review every line of code that's written. So, if you put the @Immutable attribute on a class that's not immutable, you're gonna get called on it. Ask Jason, I've done it several times. – Brandon DuRette Oct 15 '08 at 04:44
  • 2
    By the way, the idea for the @Immutable attribute is not original, it comes from Java Concurrency In Practice by Brian Goetz. – Brandon DuRette Oct 15 '08 at 04:45
  • 1
    Also, @SCdF, you're always relying on the author to if a class is immutable or not in Java, and even then there are ways of changing any member variables. The Annotation is probably the best of what YOU might call the worst. – Henry B Oct 15 '08 at 08:33
  • The annotation is a great idea. I'm not sure it meets all my needs, because of the danger people would apply it indiscriminately. – mcherm Oct 15 '08 at 13:11
  • I'm not saying the annotation is wrong, I'm saying that it's like security by obscurity-- it gives a false sense of security. In this case a false comfort that your code is immutable. – SCdF Oct 15 '08 at 19:16
  • Also, all you've done is made sure that the original author (assuming he typed the @immutable himself) has *possibly* thought about what that means. You have no such guarantee on people who extend or alter the class in a year and never even *notice* the @immutable at the top. – SCdF Oct 15 '08 at 19:17
  • @SCdF: Yes, but welcome to software development. It's true of *everything* that someone might come along later and abuse it. They might not read the JavaDoc. They might not grok the spirit of the methods. They might not understand how the class is *now* used, as opposed to the design. – Jason Cohen Mar 04 '09 at 16:30
8

Basically no.

You could build a giant white-list of accepted classes but I think the less crazy way would be to just write in the documentation for the collection that everything that goes is this collection must be immutable.

Edit: Other people have suggested having an immutable annotation. This is fine, but you need the documentation as well. Otherwise people will just think "if I put this annotation on my class I can store it in the collection" and will just chuck it on anything, immutable and mutable classes alike. In fact, I would be wary of having an immutable annotation just in case people think that annotation makes their class immutable.

SCdF
  • 57,260
  • 24
  • 77
  • 113
  • 1
    Also, in the JCIP book there is discussion about effectively immutable classes like java.util.Date, which in practice are used as immutable even if they aren't – ddimitrov Oct 15 '08 at 13:14
4

This could be another hint:

If the class has no setters then it cannot be mutated, granted the parameters it was created with are either "primitive" types or not mutable themselves.

Also no methods could be overridden, all fields are final and private,

I'll try to code something tomorrow for you, but Simon's code using reflection looks pretty good.

In the mean time try to grab a copy of the "Effective Java" book by Josh Block, it has an Item related to this topic. While is does not for sure say how to detect an immutable class, it shows how to create a good one.

The item is called: "Favor immutability"

Updated link: https://www.amazon.com/Effective-Java-Joshua-Bloch/dp/0134685997

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • 1
    The book link has gone stale. Here's the latest version of the book (which I highly recommend, and have read through many times): https://smile.amazon.com/Effective-Java-Joshua-Bloch/dp/0134685997 – chaotic3quilibrium Jan 10 '23 at 15:19
4

In my code, I am creating a collection of objects which will be accessed by various threads in a fashion that is only safe if the objects are immutable.

Not a direct answer to your question, but keep in mind that objects that are immutable are not automatically guaranteed to be thread safe (sadly). Code needs to be side-effect free to be thread safe, and that's quite a bit more difficult.

Suppose you have this class:

class Foo {
  final String x;
  final Integer y;
  ...

  public bar() {
    Singleton.getInstance().foolAround();
  }
}

Then the foolAround() method might include some non-thread safe operations, which will blow up your app. And it's not possible to test for this using reflection, as the actual reference can only be found in the method body, not in the fields or exposed interface.

Other than that, the others are correct: you can scan for all declared fields of the class, check if every one of them is final and also an immutable class, and you're done. I don't think methods being final is a requirement.

Also, be careful about recursively checking dependent fields for immutability, you might end up with circles:

class A {
  final B b; // might be immutable...
}

class B {
  final A a; // same so here.
}

Classes A and B are perfectly immutable (and possibly even usable through some reflection hacks), but naive recursive code will go into an endless loop checking A, then B, then A again, onwards to B, ...

You can fix that with a 'seen' map that disallows cycles, or with some really clever code that decides classes are immutable if all their dependees are immutable only depending on themselves, but that's going to be really complicated...

Martin Probst
  • 9,497
  • 6
  • 31
  • 33
  • These are both really good warnings, neither of which I had really considered. I doubt that I need to defend against the recursively contained immutable object (simplest case would be an immutable object containing itself in a field!), but the other is a bit of a danger. – mcherm Oct 15 '08 at 13:36
3

You can use AOP and @Immutable annotation from jcabi-aspects:

@Immutable
public class Foo {
  private String data;
}
// this line will throw a runtime exception since class Foo
// is actually mutable, despite the annotation
Object object = new Foo();
yegor256
  • 102,010
  • 123
  • 446
  • 597
3

You Can Ask your clients to add metadata (annotations) and check them at runtime with reflection, like this:

Metadata:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CLASS)
public @interface Immutable{ }

Client Code:

@Immutable
public class ImmutableRectangle {
    private final int width;
    private final int height;
    public ImmutableRectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
}

Then by using reflection on the class, check if it has the annotation (I would paste the code but its boilerplate and can be found easily online)

Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
  • How would you stop people from just putting that annotation on non-immutable classes? – SCdF Oct 15 '08 at 02:21
  • You don't stop them. If you can't follow instructions how to use something, you shouldn't try to program it. – Simon Lehmann Oct 15 '08 at 02:25
  • @Simon, OK, so then what's the point of the annotation at all? Can't you just assume that they are smart enough to read the documentation about the collection and thus know that it's only for immutable things? – SCdF Oct 15 '08 at 02:31
  • @SCdF, I tried to give a cost-effective approach, maybe he can make it work. Saying "NO, YOU CANT" is the same as not saying anything at all (or worst) – Pablo Fernandez Oct 15 '08 at 02:34
  • Now that I have thought about it a bit more, I have to partially agree, that having an annotation might lead to confusion and misunderstandings. – Simon Lehmann Oct 15 '08 at 02:57
  • I fear that some of our developers would incompletely understand the concept and misuse the annotation. Otherwise, it would be an excellent solution. Combined with validation it might work perfectly. – mcherm Oct 15 '08 at 13:12
3

why do all the recommendations require the class to be final? if you are using reflection to check the class of each object, and you can determine programmatically that that class is immutable (immutable, final fields), then you don't need to require that the class itself is final.

james
  • 191
  • 1
  • 2
2

Like the other answerers already said, IMHO there is no reliable way to find out if an object is really immutable.

I would just introduce an interface "Immutable" to check against when appending. This works as a hint that only immutable objects should be inserted for whatever reason you're doing it.

interface Immutable {}

class MyImmutable implements Immutable{...}

public void add(Object o) {
  if (!(o instanceof Immutable) && !checkIsImmutableBasePrimitive(o))
    throw new IllegalArgumentException("o is not immutable!");
  ...
}
Daniel Hiller
  • 3,415
  • 3
  • 23
  • 33
1

To my knowledge, there is no way to identify immutable objects that is 100% correct. However, I have written a library to get you closer. It performs analysis of bytecode of a class to determine if it is immutable or not, and can execute at runtime. It is on the strict side, so it also allows whitelisting known immutable classes.

You can check it out at: www.mutabilitydetector.org

It allows you to write code like this in your application:

/*
* Request an analysis of the runtime class, to discover if this
* instance will be immutable or not.
*/
AnalysisResult result = analysisSession.resultFor(dottedClassName);

if (result.isImmutable.equals(IMMUTABLE)) {
    /*
    * rest safe in the knowledge the class is
    * immutable, share across threads with joyful abandon
    */
} else if (result.isImmutable.equals(NOT_IMMUTABLE)) {
    /*
    * be careful here: make defensive copies,
    * don't publish the reference,
    * read Java Concurrency In Practice right away!
    */
}

It is free and open source under the Apache 2.0 license.

Grundlefleck
  • 124,925
  • 25
  • 94
  • 111
  • Doesn't work fine with Java 11 and List<> fields wrapped with List.copyOf() which makes it immutable. Mutabilitydetector does fail on that point if not wrapped in Collections.unmodifiableList() – Sebastian Barth Apr 01 '20 at 21:46
  • I'll need to raise an issue for that. Should not be difficult to recognise new Java 11 immutable collection constructors. – Grundlefleck Apr 03 '20 at 13:44
1

Try this:

public static boolean isImmutable(Object object){
    if (object instanceof Number) { // Numbers are immutable
        if (object instanceof AtomicInteger) {
            // AtomicIntegers are mutable
        } else if (object instanceof AtomicLong) {
            // AtomLongs are mutable
        } else {
            return true;
        }
    } else if (object instanceof String) {  // Strings are immutable
        return true;
    } else if (object instanceof Character) {   // Characters are immutable
        return true;
    } else if (object instanceof Class) { // Classes are immutable
        return true;
    }

    Class<?> objClass = object.getClass();

    // Class must be final
    if (!Modifier.isFinal(objClass.getModifiers())) {
            return false;
    }

    // Check all fields defined in the class for type and if they are final
    Field[] objFields = objClass.getDeclaredFields();
    for (int i = 0; i < objFields.length; i++) {
            if (!Modifier.isFinal(objFields[i].getModifiers())
                            || !isImmutable(objFields[i].getType())) {
                    return false;
            }
    }

    // Lets hope we didn't forget something
    return true;
}
  • Does not work when the object class has cycles (e.g. `class MyNode { MyNode parent; public MyNode() {} public MyNode(MyNode parent) { this.parent = parent; } }`) : you will get a `StackOverflowError`. – Julien Kronegg Jun 15 '18 at 22:16
  • This does not work for all classes. For example, `BigInteger` extends `Number` and the javadoc states that it is an immutable class, but nor the `BigInteger` class nor its methods are `final`, so the class can be overriden and the child class may change the `BigInteger` class behavior. – Julien Kronegg Jun 15 '18 at 22:22
0

I appreciate and admire the amount of work Grundlefleck has put into his mutability detector, but I think it is a bit of an overkill. You can write a simple but practically very adequate (that is, pragmatic) detector as follows:

(note: this is a copy of my comment here: https://stackoverflow.com/a/28111150/773113)

First of all, you are not going to be just writing a method which determines whether a class is immutable; instead, you will need to write an immutability detector class, because it is going to have to maintain some state. The state of the detector will be the detected immutability of all classes which it has examined so far. This is not only useful for performance, but it is actually necessary because a class may contain a circular reference, which would cause a simplistic immutability detector to fall into infinite recursion.

The immutability of a class has four possible values: Unknown, Mutable, Immutable, and Calculating. You will probably want to have a map which associates each class that you have encountered so far to an immutability value. Of course, Unknown does not actually need to be implemented, since it will be the implied state of any class which is not yet in the map.

So, when you begin examining a class, you associate it with a Calculating value in the map, and when you are done, you replace Calculating with either Immutable or Mutable.

For each class, you only need to check the field members, not the code. The idea of checking bytecode is rather misguided.

First of all, you should not check whether a class is final; The finality of a class does not affect its immutability. Instead, a method which expects an immutable parameter should first of all invoke the immutability detector to assert the immutability of the class of the actual object that was passed. This test can be omitted if the type of the parameter is a final class, so finality is good for performance, but strictly speaking not necessary. Also, as you will see further down, a field whose type is of a non-final class will cause the declaring class to be considered as mutable, but still, that's a problem of the declaring class, not the problem of the non-final immutable member class. It is perfectly fine to have a tall hierarchy of immutable classes, in which all the non-leaf nodes must of course be non-final.

You should not check whether a field is private; it is perfectly fine for a class to have a public field, and the visibility of the field does not affect the immutability of the declaring class in any way, shape, or form. You only need to check whether the field is final and its type is immutable.

When examining a class, what you want to do first of all is to recurse to determine the immutability of its super class. If the super is mutable, then the descendant is by definition mutable too.

Then, you only need to check the declared fields of the class, not all fields.

If a field is non-final, then your class is mutable.

If a field is final, but the type of the field is mutable, then your class is mutable. (Arrays are by definition mutable.)

If a field is final, and the type of the field is Calculating, then ignore it and proceed to the next field. If all fields are either immutable or Calculating, then your class is immutable.

If the type of the field is an interface, or an abstract class, or a non-final class, then it is to be considered as mutable, since you have absolutely no control over what the actual implementation may do. This might seem like an insurmountable problem, because it means that wrapping a modifiable collection inside an UnmodifiableCollection will still fail the immutability test, but it is actually fine, and it can be handled with the following workaround.

Some classes may contain non-final fields and still be effectively immutable. An example of this is the String class. Other classes which fall into this category are classes which contain non-final members purely for performance monitoring purposes (invocation counters, etc.), classes which implement popsicle immutability (look it up), and classes which contain members that are interfaces which are known to not cause any side effects. Also, if a class contains bona fide mutable fields but promises not to take them into account when computing hashCode() and equals(), then the class is of course unsafe when it comes to multi-threading, but it can still be considered as immutable for the purpose of using it as a key in a map. So, all these cases can be handled in one of two ways:

  1. Manually adding classes (and interfaces) to your immutability detector. If you know that a certain class is effectively immutable despite the fact that the immutability test for it fails, you can manually add an entry to your detector which associates it with Immutable. This way, the detector will never attempt to check whether it is immutable, it will always just say 'yes, it is.'

  2. Introducing an @ImmutabilityOverride annotation. Your immutability detector can check for the presence of this annotation on a field, and if present, it may treat the field as immutable despite the fact that the field may be non-final or its type may be mutable. The detector may also check for the presence of this annotation on the class, thus treating the class as immutable without even bothering to check its fields.

I hope this helps future generations.


EDIT in 2023

I ended up writing a library called Bathyscaphe that implements all of the above. Although indeed a lot more simple than MutabilityDetector, it ended up being far more complicated than I imagined, so I would strongly recommend that you use this library instead of attempting to implement the above by yourself.

Bathyscaphe can be found here: https://github.com/mikenakis/Bathyscaphe

In my opinion, static analysis tools such as MutabilityDetector (see Grundlefleck's answer) can be useful at certain times and under certain scenarios, but they do not (and cannot) provide a complete solution to the problem at all times. A complete solution requires runtime checking as I explain on my blog here: https://blog.michael.gr/2022/05/bathyscaphe.html, and that's why I have written Bathyscaphe.

To address the concern expressed by Martin Probst in his answer to this question, Bathyscaphe will also help you check for thread-safety, although this branch of checks relies heavily on annotations that you add to your code, so naturally, Bathyscaphe will only give correct answers if the annotations are correct. But it is still better than coding in the dark.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
0

Something which works for a high percentage of builtin classes is test for instanceof Comparable. For the classes which are not immutable like Date, they are often treated as immutable in most cases.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130