# Takes: a Java web framework that refuses nulls and static methods

> Takes is a Java 8 web framework built on four prohibitions, no nulls, no public static methods, no mutable classes and no instanceof or reflection, with no configuration files and templates, JSON, XML and XSLT support. It suits developers who want object-oriented constraints enforced by the framework rather than by convention.

**yegor256/takes** — True Object-Oriented Java Web Framework without NULLs, Static Methods, Annotations, and Mutable Objects

- Repository: https://github.com/yegor256/takes
- Website: https://www.takes.org/
- Stars: 878 · Forks: 218
- Language: Java
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/yegor256-takes

## Four prohibitions, stated as the product

The framework is described as a true object-oriented and immutable Java 8 web development framework, and the key benefits are given as four fundamental principles. There is not a single null anywhere in it. There is not a single public static method. There is not a single mutable class. And there is not a single instanceof keyword, type casting or reflection. Each prohibition links to a page explaining why that thing is bad, which tells you these are arguments rather than preferences. The scale of the commitment is what makes the framework interesting, because a library that merely discourages nullable returns is a convention, while one that cannot express a nullable value is a different kind of tool. The cost of that commitment is equally clear from what is excluded, since reflection-based libraries and frameworks that rely on it are simply not usable, and the documentation is upfront that the design is opposed to that whole style. There is also a note that there are no configuration files at all, which removes the XML or properties file that a Java web application usually starts with.

## The quick start is a dozen lines and a jar

The first example is a complete server, and reading it tells you the object model. You build a fork of facets, a regex facet that matches the root path and returns a text response, wrap it in a fork, and hand that to the basic front, then start it:

```java
import org.takes.http.Exit;
import org.takes.http.FtBasic;
import org.takes.facets.fork.FkRegex;
import org.takes.facets.fork.TkFork;
public final class App {
  public static void main(final String... args) throws Exception {
    new FtBasic(
      new TkFork(new FkRegex("/", "hello, world!")), 8080
    ).start(Exit.NEVER);
  }
}
```

The naming is the design. The front is the HTTP server wrapper, the fork is a decorator that composes facets, and the regex facet matches a path and produces a body. Everything is an object implementing interfaces, and the composition is by wrapping rather than by configuring. The build is the same idea in a different tool, since the jar with dependencies is compiled against and run with the standard classpath commands:

```bash
javac -cp takes-1.26.0-jar-with-dependencies.jar App.java
```

```bash
java -Dfile.encoding=UTF-8 -cp takes-1.26.0-jar-with-dependencies.jar:. App
```

The port is passed to the front, the exit condition is an object rather than a flag, and the whole thing starts a server on port 8080 that answers every request at the root with a plain-text page.

## The encoding caveat is the first thing that will bite you

There is a caution box in the quick start and it is worth taking seriously. The note asks you to pay attention that UTF-8 encoding is set on the command line, because the entire framework relies on your default Java encoding, which is not necessarily UTF-8 by default. The reason the library does not hard-code UTF-8 is stated as well, that it would be against the entire idea of Java localisation, according to which a user should always have a choice of encoding and language selection, and that the code uses the default charset everywhere. The reasoning is consistent with the rest of the design, where the framework declines to make choices on your behalf, but the practical consequence is that a Takes application started without that system property can produce mangled output on a machine whose default is not UTF-8, and the failure will look like a bug in the framework rather than a missing command line argument. It is the kind of constraint that a team should write into its start scripts rather than into a readme, because the readme is only read once.

## What the framework gives you out of the box

The traditional features are listed after the principles, and the list is short enough to be honest about. There is hit-refresh debugging, which lets you change a page and see the change without a full restart. There is XML with XSLT, so the browser can transform an XML response using a stylesheet, and there is JSON support, and a RESTful style of endpoints, and templates including Apache Velocity. What is explicitly not supported is stated just as firmly, and WebSockets appear on that list, described as something that will not be supported. That is a real constraint for a modern web application, since a live dashboard or a chat feature is out of reach, and it is a consequence of the design rather than an oversight. Two open source systems that use the framework are named, which is a useful signal about whether it holds up outside a demo, and the project also links to a blog post about the 1.26.0 release as further reading. The repository is built on Maven and published to Maven Central under the org.takes coordinates, with a javadoc badge, a test coverage badge and a project status page.

## Maven and Gradle builds, and the hit-refresh profile

The build instructions show the same principle applied to configuration. The Maven setup declares a single dependency on the takes artifact at version 1.26.0, and then a profile whose only job is to start the server before the integration tests run, using the exec plugin bound to the pre-integration-test phase with your own main class and a port property passed as an argument. Running it is one command:

```bash
mvn clean integration-test -Phit-refresh -Dport=8080
```

The profile name is the hit-refresh mode, which is the feature where the server stays up while you edit. The documentation also covers a Gradle path, unit testing, integration testing and a larger example with a front interface and a back interface, which is the usual way to show a framework handling more than one page. The content list is long enough to suggest a well-documented project, with sections for templates and specifically for Velocity templates, static resources, hit-refresh debugging, request methods, request parsing, form processing, exception handling, redirects, the two lightweight object formats the framework provides, GZIP compression, SSL configuration, authentication, command line arguments, logging, directory layout, optional dependencies, backward compatibility and a version pattern for RESTful APIs. That last set is the most useful to skim, because backward compatibility and a version pattern are the two things you need before you commit to a framework.

## Building on the framework rather than just using it

The framework is not only usable, it is extensible, and the readme shows the entry point. If you need to run inside a servlet container you create a Take with a constructor accepting the servlet context, and the class implements the Take interface with a field for the context. That is the extension seam, and it is the same object model as the quick start, with the container supplied rather than the server. The repository layout is a Maven project with the source under src, a pom at the root, a licence file and a licences directory, a REUSE configuration, a citation file, a renovate configuration, and a set of project management files including a 0pdd configuration, a pdd file and a rultor configuration. The release history is where the interesting detail sits, because the version numbers carry their change notes. The 1.25.1 release is named for a parser bug where carriage return and line feed characters preceding the HTTP method in a request tripped up the parser, and 1.26.0 is named for a tooling upgrade. A bug fix in the HTTP parser is the kind of release note that tells you what the framework spends its time on, and the last push on 2026-10-20 suggests the work is still going.

## Conclusion

Takes is a good fit for a Java developer who wants the object-oriented constraints enforced rather than recommended, because the framework refuses to hand you a null, a static utility or a mutable object, and because it starts a working server from a dozen lines with no configuration file. It is the wrong choice if you need WebSockets, which the documentation lists as something the project will not support, and it is the wrong choice if your application depends on reflection-based frameworks, since reflection is one of the four prohibited mechanisms. It is also the wrong choice if you need the wider Java ecosystem, since the design excludes a large part of it by intent. Before adopting it, read the quick start and note the encoding caveat, because the framework relies on the default Java encoding and the documentation asks you to set it explicitly on the command line. The project is MIT licensed, the last push was on 2026-10-20, and the current release is 1.26.0 from 2026-04-28.

## FAQ

### What is Takes and what does it forbid?

It is a true object-oriented and immutable Java 8 web framework with four fundamental principles: not a single null, not a single public static method, not a single mutable class, and not a single instanceof keyword, type casting or reflection. There are also no configuration files to write.

### How do I start a Takes server?

With a small main class that builds a regex facet returning a response, wraps it in a fork, hands that to the basic HTTP front and starts it on a port with an exit condition object. The class is compiled against the jar with dependencies and run with the standard classpath commands, and it answers every request at the root path with a plain-text page.

### What encoding caveat comes with Takes?

The framework relies on the default Java encoding, which is not necessarily UTF-8, so the documentation asks you to set it on the command line with the file.encoding Java argument. It is not hard-coded because the project treats that as against the idea of Java localisation, and it uses the default charset throughout the code.

### Does Takes support WebSockets?

No. The documentation lists WebSockets among the things that are not and will not be supported, alongside the reflection-based approach the framework deliberately excludes. The features that are provided out of the box include hit-refresh debugging, XML with XSLT, JSON, RESTful endpoints and templates including Apache Velocity.

### How is a Takes project built and tested?

With Maven, declaring the takes dependency and a profile that starts the server in the pre-integration-test phase through the exec plugin, then running one command that cleans, runs the integration tests with the hit-refresh profile and passes the port. There is also a Gradle path, unit and integration testing instructions, and a larger example with separate front and back interfaces.

## Sources

- [License: MIT](https://github.com/yegor256/takes/blob/master/LICENSE)
- [Project website](https://www.takes.org/)
- [README](https://github.com/yegor256/takes/blob/master/README.md)
- [Releases](https://github.com/yegor256/takes/releases)
- [yegor256/takes on GitHub](https://github.com/yegor256/takes)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yegor256-takes
