Fundamentals 4 min read

Is java.lang.String Truly Immutable? Reflection Bypass in Java 11 and Prevention in Java 17

This article explains how java.lang.String, traditionally considered immutable, can be altered via reflection in Java 11, how Java 17 blocks such modifications with exceptions, and demonstrates using StackTrace-based checks and other practical applications for security and debugging in Java.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
Is java.lang.String Truly Immutable? Reflection Bypass in Java 11 and Prevention in Java 17

Java developers often assume that java.lang.String is immutable, but the article shows that in Java 11 reflection can change a String's internal value, breaking the immutability guarantee.

A real‑world incident is cited where clearing a String via reflection caused a business‑critical failure (link to the analysis article).

Starting with Java 17, attempts to modify a String through reflection trigger an InaccessibleObjectException , effectively preventing the unsafe operation.

The article details the internal checks performed when Field#setAccessible is invoked, including module, package and access‑level validations, illustrated with several screenshots of the security checks.

To enforce custom security policies, the author presents a StackTrace‑based validation technique. The provided Demo class extracts the current stack trace, verifies that the caller originates from the com.example.demo package and the method name is test , and throws an InaccessibleObjectException otherwise.

package com.example.demo;

import java.lang.reflect.InaccessibleObjectException;

public class Demo {
    public static void main(String[] args) throws ReflectiveOperationException {
        test();
        System.out.println("test....");
        doDo();
    }

    private static void test() {
        doDo();
    }

    private static void doDo() {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        StackTraceElement stackTraceElement = stackTrace[1];
        if (stackTraceElement.getClassName().startsWith("com.example.demo") &&
            stackTraceElement.getMethodName().equals("test")) {
            System.out.println("doDo.....");
        }
        throw new InaccessibleObjectException("doDo 方法不能被调用");
    }
}

Running the program shows that calling doDo() directly from main throws the exception, while invoking it through test() is allowed, as demonstrated by the accompanying screenshot.

The article also lists other practical uses of StackTrace information: retrieving the Spring Boot main class ( SpringApplication#deduceMainApplicationClass ), extracting exception stacks in Logback ( CallerData#extract ), detecting lock order violations with Guava's CycleDetectingLockFactory , identifying method callers, and validating layered‑architecture constraints.

In conclusion, StackTrace data can be leveraged for security checks and creative implementations, but because obtaining stack traces is costly, Java 9 introduced java.lang.StackWalker as a more efficient alternative to StackTraceElement .

JavaReflectionsecurityStackTraceString immutability
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.