[HN Gopher] Fernflower Java Decompiler
       ___________________________________________________________________
        
       Fernflower Java Decompiler
        
       Author : bartekpacia
       Score  : 122 points
       Date   : 2025-09-25 20:20 UTC (4 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | krackers wrote:
       | Is there a standalone gui version similar to jd-gui?
        
         | 0x1ceb00da wrote:
         | Intellij
        
         | enoent wrote:
         | https://bytecodeviewer.com/
        
           | fioan89 wrote:
           | I find https://github.com/nbauma109/jd-gui-duo better than
           | bytecodeviewer. At least on macOS it is much more stable, the
           | UI is actually usable.
        
         | Igor_Wiwi wrote:
         | There is a web application which allows to navigate and edit
         | jar files - https://jar.tools/ (I am the creator)
        
       | userbinator wrote:
       | _The correct name is Fernflower, not FernFlower._
       | 
       | I found this amusing, from a Java perspective. The 3-character
       | command-line options are also very "not Java-ish". However, since
       | this one is also written in Java, a good test is if it can
       | decompile itself perfectly and the result recompiled to a
       | matching binary; much like how bootstrapping a compiler involves
       | compiling itself and checking for the existence of the fixed-
       | point.
        
       | mudkipdev wrote:
       | https://github.com/Vineflower/vineflower
        
         | yardstick wrote:
         | Why would one choose this over the original?
        
           | h4ch1 wrote:
           | After a little research it seems like it's main focus in on
           | decompiled code readability.
           | 
           | https://old.reddit.com/r/java/comments/ue8u59/new_open_sourc.
           | ..
           | 
           | A little more info in this thread as well:
           | 
           | https://old.reddit.com/r/java/comments/ue8u59/new_open_sourc.
           | ..
           | 
           | (It was earlier named Quiltflower and is actually a
           | combination of multiple Fernflower forks from its' gh README)
           | 
           | Would ideally expect the project site/github to list out
           | how's the fork different though.
        
       | brap wrote:
       | I know you probably don't want an LLM in your decompiler, but
       | assigning meaningful names could be a good task for an LLM.
        
         | p0w3n3d wrote:
         | One day I was using ghidra to decompile something to find out
         | how it works, and the LLM helped a lot. It was a game changer
         | in refactoring of the decompiled assembly-that-looked-like-c
         | language.
        
         | Hackbraten wrote:
         | There's some prior art on this [0] [1], and it's worked
         | decently well for me on obfuscated JS.
         | 
         | [0]: https://thejunkland.com/blog/using-llms-to-reverse-
         | javascrip...
         | 
         | [1]:
         | https://github.com/jehna/humanify/blob/main/README.md#exampl...
        
           | viraptor wrote:
           | It's also good as picking up patterns which are common
           | enough, but may not be known to everyone. For example I
           | couldn't tell that some function was doing CRC via a lookup
           | table - but Claude knew.
        
             | BobbyTables2 wrote:
             | Often googling the first few entries of such tables will
             | show CRC implementations. Same for SHA hash constants...
        
               | viraptor wrote:
               | The tables depend on the CRC parameters and in my case
               | there would be no Google hits - a unique setup was used.
        
         | cogman10 wrote:
         | That'd make sense if the jar is obfuscated. Java preserves
         | method and class names by default.
        
       | stevoski wrote:
       | The story behind the Fernflower Java decompiler is here:
       | https://blog.jetbrains.com/idea/2024/11/in-memory-of-stiver/
        
         | vbezhenar wrote:
         | Stiver also created Flibusta - absolutely huge online library
         | of (mostly pirated) Russian books.
        
       | asplake wrote:
       | > Fernflower is the first actually working analytical decompiler
       | for Java and probably for a high-level programming language in
       | general.
       | 
       | That really deserves a link. What is an "analytical" decompiler?
        
         | jakewins wrote:
         | Someone apparently had the exact same question in 2020:
         | https://stackoverflow.com/questions/62298929/what-is-an-anal...
         | 
         | Answer is pretty vague though, but sounds like it's about not
         | trying to "reverse" what the compiler did, but rather try and
         | "analytically" work put what source code would likely have
         | yielded the byte code it's looking at?
        
           | rhdunn wrote:
           | Yes, that's what it is doing.
           | 
           | If you have a block of code a compiler will compile a
           | language expression or statement into a particular set of
           | assembly/bytecode instructions. For example converting `a +
           | b` to `ADD a b`.
           | 
           | A reversing decompiler will look at the `ADD a b` and produce
           | `a + b` as the output. This is the simplest approach as it is
           | effectively just a collection of these types of mapping.
           | While this works, it can be harder to read and noisier than
           | the actual code. This is because:
           | 
           | 1. it does not handle annotations like @NotNull correctly --
           | these are shown as `if (arg == null) throw ...` instead of
           | the annotation because the if/throw is what the compiler
           | generated for that annotation;
           | 
           | 2. it doesn't make complex expressions readable;
           | 
           | 3. it doesn't detect optimizations like unrolling loops,
           | reordering expressions, etc.
           | 
           | For (1) an analytical decompiler can recognize the `if (arg
           | == null) throw` expression at the start of the function and
           | map that to a @NotNull annotation.
           | 
           | Likewise, it could detect other optimizations like loop
           | unrolling and produce better code for that.
        
             | vbezhenar wrote:
             | I'm not sure that @NotNull example is appropriate. Java
             | compiler does not add any checks for @NotNull annotations.
             | Those annotations exist for IDE and linting tools, compiler
             | doesn't care. May be there are Java-like languages like
             | Lombok or non-standard compilers which do add those checks,
             | but I think that Java decompiler shouldn't do assumptions
             | of these additional tools.
        
               | rhdunn wrote:
               | https://www.jetbrains.com/help/idea/annotating-source-
               | code.h...
               | 
               | > When you compile your project with IntelliJ IDEA build
               | tool, the IDE adds assertions to all code elements
               | annotated with @NotNull. These assertions will throw an
               | error if the elements happen to be null at runtime.
        
               | vbezhenar wrote:
               | That's not java compiler. That's intellij compiler. I'd
               | say that's very weird anti-feature, because your build in
               | IDE and maven will work differently.
        
               | wokkel wrote:
               | When using Lombok it will use a compiler plugin for this
               | so maven builds have @nonnull generated as if-statements.
               | I dont know if intellij uses their own plugin but they do
               | support Lombok in maven projects, so maybe thats where
               | this is coming from. Afaik intellij has no built in
               | compiler but relies on java .
        
               | Bjartr wrote:
               | Lombok hijacks the compiler to do it's own thing, and
               | violates the contract Java compiler plugins are supposed
               | to follow.
               | 
               | See this comment by an OpenJDK tech lead:
               | https://news.ycombinator.com/item?id=37666793
        
               | lisbbb wrote:
               | I was initially impressed with Lombok and then ran into
               | all the downsides of it and it was institutionally
               | abandoned at one particular firm I was with (100s of
               | devs).
        
         | lbalazscs wrote:
         | The link about Stiver has some details:
         | 
         | > Stiver decided to write his own decompiler as a side project.
         | To overcome the weaknesses of existing alternatives, he took a
         | different approach. After reading the bytecode, he constructed
         | a control-flow graph in static single-assignment form, which is
         | much better to express the program semantics abstracting the
         | particular shape of bytecode. At the beginning of this project,
         | Stiver knew little about static analysis and compiler design
         | and had to learn a lot, but the effort was worth it. The
         | resulting decompiler produced much better results than anything
         | available at that time. It could even decompile the bytecode
         | produced by some obfuscators without any explicit support.
         | 
         | https://blog.jetbrains.com/idea/2024/11/in-memory-of-stiver/
        
       | p0w3n3d wrote:
       | Is it only me or fernflower does not put the code in the correct
       | lines, and the debugging fails to navigate over the code in the
       | IntelliJ IDEA?
        
         | bartekpacia wrote:
         | This sounds like a bug - I'd appreciate it if you could share
         | an example of such behavior.
         | 
         | [I work at JetBrains]
        
         | gf000 wrote:
         | I mean, in the general case is it not impossible to "put the
         | code in the correct lines"?
         | 
         | Maybe I'm just misunderstanding you, but even if the bytecode
         | sequence is reconstructed as the original code that produced
         | it, stuff like whitespace and comments are simply lost with no
         | ways to recover.
         | 
         | (Also, local variable names, certain annotations depending on
         | their retention level, etc)
        
       | nunobrito wrote:
       | Can the decompiled result be compiled again?
        
         | jeroenhd wrote:
         | It's not a perfect decompiler, some obfuscated code gets
         | decompiled into commented-out bytecode.
         | 
         | However, most of the time it'll output perfectly valid Java
         | code that'll compile if you just create the necessary
         | maven/ant/gradle build configuration to get all of the sources
         | loaded correctly.
        
         | dunham wrote:
         | I've actually had this fix a bug before. An O(n^2) issue adding
         | a character at time to a string inside a loop.
         | 
         | I had decompiled the class, fixed the issue, checked in the
         | original decompiled source and then the change. Then a coworker
         | pointed out that the original decompiled source also fixed the
         | issue.
         | 
         | After a bit of digging, I learned that hotspot compiler had
         | code to detect and fix the issue, but it was looking for the
         | pattern generated by a modern compiler, and the library was
         | compiled with an older compiler.
         | 
         | (It's been a while, but I think it was the JAI library, and the
         | issue was triggered by long comments in a PNG.)
        
       | nneonneo wrote:
       | jadx (https://github.com/skylot/jadx) is similar, but for Android
       | Java (Dalvik bytecode). I use it extensively and it works very
       | well.
       | 
       | Over in .NET land, dnSpy (https://github.com/dnSpyEx/dnSpy) works
       | very well, even on many obfuscated binaries.
        
       | hunterpayne wrote:
       | I'm using this decompiler in my project right now. Its the best
       | of the bunch and Jetbrains actively maintains it with good
       | support.
        
       | BinaryIgor wrote:
       | ...written in Java! Recursion going strong :)
        
       ___________________________________________________________________
       (page generated 2025-09-29 23:01 UTC)