GraphQL, JavaScript, Preprocessor, SQL and more in Manifold

GraphQL, JavaScript, Preprocessor, SQL and more in Manifold

In this final installment of the Manifold series we discuss the final integrations and review the benefits. I also discuss using it in my new project.

We reached the final installment of our Manifold series but not the end of its remarkable capabilities. Throughout this series, we have delved into various aspects of Manifold, highlighting its unique features and showcasing how it enhances Java development. In this article, we will cover some of the remaining features of Manifold, including its support for GraphQL, integration with JavaScript, and the utilization of a preprocessor. By summarizing these features and reflecting on the knowledge gained throughout the series, I hope to demonstrate the power and versatility of Manifold.

Expanding Horizons with GraphQL Support

GraphQL, a relatively young technology, has emerged as an alternative to REST APIs. It introduced a specification for requesting and manipulating data between client and server, offering an arguably more efficient and streamlined approach. However, GraphQL can pose challenges for static languages like Java.

Thankfully, Manifold comes to the rescue by mitigating these challenges and making GraphQL accessible and usable within Java projects. By removing the rigidness of Java and providing seamless integration with GraphQL, Manifold empowers developers to leverage this modern API style.

E.g. for this graphql file taken from the Manifold repository:

query MovieQuery($genre: Genre!, $title: String, $releaseDate: Date) {
    movies(genre: $genre, title: $title, releaseDate: $releaseDate) {
        id
        title
        genre
        releaseDate
    }
}

query ReviewQuery($genre: Genre) {
    reviews(genre: $genre) {
        id
        stars
        comment
        movie {
            id
            title
        }
    }
}

mutation ReviewMutation($movie: ID!, $review: ReviewInput!) {
    createReview(movie: $movie, review: $review) {
        id
        stars
        comment
    }
}

extend type Query {
    reviewsByStars(stars: Int) : [Review!]!
}

We can write this sort of fluent code:

var query = MovieQuery.builder(Action).build();
var result = query.request(ENDPOINT).post();
var actionMovies = result.getMovies();
for (var movie : actionMovies) {
  out.println(
    "Title: " + movie.getTitle() + "\n" +
    "Genre: " + movie.getGenre() + "\n" +
    "Year: " + movie.getReleaseDate().getYear() + "\n");
}

None of these objects need to be declared in advance, all we need are the GraphQL files.

Achieving Code Parity with JavaScript Integration

In some cases, regulatory requirements demand identical algorithms in both client and server code. This is common for cases like interest rate calculations where in the past we used Swing applications to calculate and display the rate. Since both the backend and front-end were in Java it was simple to have a single algorithm.

However, this can be particularly challenging when the client-side implementation relies on JavaScript. Manifold provides a solution by enabling the integration of JavaScript within Java projects. By placing JavaScript files alongside the Java code, developers can invoke JavaScript functions and classes seamlessly using Manifold. Under the hood, Manifold utilizes Rhino to execute JavaScript, ensuring compatibility and code parity across different environments.

E.g. this JavaScript snippet:

function calculateValue(total, year, rate) {
  var interest = rate / 100 + 1;
  return parseFloat((total * Math.pow(interest, year)).toFixed(4));
}

Can be invoked from Java as if it was a static method:

var interest = Calc.calculateValue(4,1999, 5);
System.out.println(interest);

Preprocessor for Java

While preprocessor-like functionality may seem unnecessary in Java due to its portable nature and JIT compilation, there are scenarios where conditional code becomes essential. For instance, when building applications that require different behavior in on-premises and cloud environments, configuration alone may not suffice. It would technically work, but it might leave proprietary bytecode in on-site deployments and that isn’t something we would want. There are workarounds for this but they are often very heavy-handed for something relatively simple.

Manifold addresses this need by offering a preprocessor-like capability. By defining values in build.properties or through environment variables and compiler arguments, developers can conditionally execute specific code paths. This provides flexibility and control without resorting to complex build tricks or platform-specific code.

With Manifold, we can write preprocessor code such as:

#if SERVER_ON_PREM
    onPremCode();
#elif SERVER_CLOUD
    cloudCode();
#else
    #error “Missing definition: SERVER_ON_PREM or SERVER_CLOUD”
#endif

Reflecting on Manifold's Power

Throughout this series, we have explored the many features of Manifold, including type-safe reflection, extension methods, operator overloading, property support, and more. These features demonstrate Manifold's commitment to enhancing Java development and bridging the gap between Java and modern programming paradigms. By leveraging Manifold, developers can achieve cleaner, more expressive code while maintaining the robustness and type safety of the Java language.

Manifold is an evolving project with many niche features I didn’t discuss in this series including the latest one SQL Support.

In a current Spring Boot project that I’m developing, I chose to use Manifold over Lombok. My main reasoning was that this is a startup project so I’m more willing to take risks. Manifold lets me tailor itself to my needs, I don’t need many of the manifold features and indeed didn’t add all of them. I will probably need to interact with GraphQL though and this was a big deciding factor when picking Manifold over Lombok. So far I am very pleased with the results and features such as entity beans work splendidly with property annotations.

I do miss the Lombok constructor's annotations though, I hope something like that will eventually make its way into Manifold. Alternatively, if I find the time I might implement this myself.

Final Word

As we conclude this journey through Manifold, it's clear that this library offers a rich set of features that elevate Java development to new heights. Whether it's simplifying GraphQL integration, ensuring code parity with JavaScript, or enabling conditional compilation through a preprocessor-like approach, Manifold empowers developers to tackle complex challenges with ease. We hope this series has provided valuable insights and inspired you to explore the possibilities that Manifold brings to your Java projects.

Don’t forget to check out the past installments in this series to get the full scope of Manifold’s power.