Logic-less and semantic Mustache templates with Java

Overview

Become a Patreon Maven Central javadoc

Handlebars.java

Logic-less and semantic Mustache templates with Java

Handlebars handlebars = new Handlebars();

Template template = handlebars.compileInline("Hello {{this}}!");

System.out.println(template.apply("Handlebars.java"));

Output:

Hello Handlebars.java!

Handlebars.java is a Java port of handlebars.

Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.

Mustache templates are compatible with Handlebars, so you can take a Mustache template, import it into Handlebars, and start taking advantage of the extra Handlebars features.

Requirements

  • Handlebars 4.3+ requires Java 8 or higher.

Getting Started

In general, the syntax of Handlebars templates is a superset of Mustache templates. For basic syntax, check out the Mustache manpage.

The Handlebars.java blog is a good place for getting started too. Javadoc is available at javadoc.io.

Maven

Stable version: Maven Central

  <dependency>
    <groupId>com.github.jknack</groupId>
    <artifactId>handlebars</artifactId>
    <version>${handlebars-version}</version>
  </dependency>

Loading templates

Templates are loaded using the TemplateLoader class. Handlebars.java provides three implementations of a TemplateLoader:

  • ClassPathTemplateLoader (default)
  • FileTemplateLoader
  • SpringTemplateLoader (see the handlebars-springmvc module)

This example loads mytemplate.hbs from the root of the classpath:

mytemplate.hbs:

Hello {{this}}!
Handlebars handlebars = new Handlebars();

Template template = handlebars.compile("mytemplate");

System.out.println(template.apply("Handlebars.java"));

Output:

Hello Handlebars.java!

You can specify a different TemplateLoader by:

TemplateLoader loader = ...;
Handlebars handlebars = new Handlebars(loader);

Templates prefix and suffix

A TemplateLoader provides two important properties:

  • prefix: useful for setting a default prefix where templates are stored.
  • suffix: useful for setting a default suffix or file extension for your templates. Default is: .hbs

Example:

TemplateLoader loader = new ClassPathTemplateLoader();
loader.setPrefix("/templates");
loader.setSuffix(".html");
Handlebars handlebars = new Handlebars(loader);

Template template = handlebars.compile("mytemplate");

System.out.println(template.apply("Handlebars.java"));

Handlebars.java will resolve mytemplate to /templates/mytemplate.html and load it.

The Handlebars.java Server

The handlebars.java server is small application where you can write Mustache/Handlebars template and merge them with data.

It is a useful tool for Web Designers.

Download from Maven Central:

  1. Go here
  2. Under the Download section click on jar

Maven:

<dependency>
  <groupId>com.github.jknack</groupId>
  <artifactId>handlebars-proto</artifactId>
  <version>${current-version}</version>
</dependency>

Usage: java -jar handlebars-proto-${current-version}.jar -dir myTemplates

Example:

myTemplates/home.hbs

<ul>
 {{#items}}
 {{name}}
 {{/items}}
</ul>

myTemplates/home.json

{
  "items": [
    {
      "name": "Handlebars.java rocks!"
    }
  ]
}

or if you prefer YAML myTemplates/home.yml:

items:
  - name: Handlebars.java rocks!

Open a browser a type:

http://localhost:6780/home.hbs

enjoy it!

Additional options:

  • -dir: set the template directory
  • -prefix: set the template's prefix, default is /
  • -suffix: set the template's suffix, default is .hbs
  • -context: set the context's path, default is /
  • -port: set port number, default is 6780
  • -content-type: set the content-type header, default is text/html

Multiple data sources per template

Sometimes you need or want to test multiple datasets over a single template, you can do that by setting a data parameter in the request URI.

Example:

http://localhost:6780/home.hbs?data=mytestdata

Please note you don't have to specify the extension file.

Helpers

Built-in helpers:

  • with
  • each
  • if
  • unless
  • log
  • block
  • partial
  • precompile
  • embedded
  • i18n and i18nJs
  • string helpers
  • conditional helpers

with, each, if, unless:

See the built-in helper documentation.

block and partial

Block and partial helpers work together to provide you Template Inheritance.

Usage:

  {{#block "title"}}
    ...
  {{/block}}

context: A string literal which defines the region's name.

Usage:

  {{#partial "title"}}
    ...
  {{/partial}}

context: A string literal which defines the region's name.

precompile

Precompile a Handlebars.java template to JavaScript using handlebars.js

user.hbs

Hello {{this}}!

home.hbs

<script type="text/javascript">
{{precompile "user"}}
</script>

Output:

<script type="text/javascript">
(function() {
  var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['user'] = template(function (Handlebars,depth0,helpers,partials,data) {
  helpers = helpers || Handlebars.helpers;
  var buffer = "", functionType="function", escapeExpression=this.escapeExpression;


  buffer += "Hi ";
  depth0 = typeof depth0 === functionType ? depth0() : depth0;
  buffer += escapeExpression(depth0) + "!";
  return buffer;});
})();
</script>

You can access the precompiled template with:

var template = Handlebars.templates['user']

By default it uses: /handlebars-v1.3.0.js to compile the template. Since handlebars.java 2.x it is also possible to use handlebars.js 2.x

Handlebars handlebars = new Handlebars();
handlebars.handlebarsJsFile("/handlebars-v2.0.0.js");

For more information have a look at the Precompiling Templates documentation.

Usage:

{{precompile "template" [wrapper="anonymous, amd or none"]}}

context: A template name. Required.

wrapper: One of "anonymous", "amd" or "none". Default is: "anonymous"

There is a maven plugin available too.

embedded

The embedded helper allow you to "embedded" a handlebars template inside a <script> HTML tag:

user.hbs

<tr>
  <td>{{firstName}}</td>
  <td>{{lastName}}</td>
</tr>

home.hbs

<html>
...
{{embedded "user"}}
...
</html>

Output:

<html>
...
<script id="user-hbs" type="text/x-handlebars">
<tr>
  <td>{{firstName}}</td>
  <td>{{lastName}}</td>
</tr>
</script>
...
</html>

Usage:

{{embedded "template"}}

context: A template name. Required.

i18n

A helper built on top of a {@link ResourceBundle}. A {@link ResourceBundle} is the most well known mechanism for internationalization (i18n) in Java.

Usage:

{{i18n "hello"}}

This require a messages.properties in the root of classpath.

Using a locale:

{{i18n "hello" locale="es_AR"}}

This requires a messages_es_AR.properties in the root of classpath.

Using a different bundle:

{{i18n "hello" bundle="myMessages"}}

This requires a myMessages.properties in the root of classpath.

Using a message format:

{{i18n "hello" "Handlebars.java"}}

Where hello is Hola {0}!, results in Hola Handlebars.java!.

i18nJs

Translate a ResourceBundle into JavaScript code. The generated code assumes you have the I18n in your application.

Usage:

{{i18nJs [locale] [bundle=messages]}}

If the locale argument is present it will translate that locale to JavaScript. Otherwise, it will use the default locale.

The generated code looks like this:

<script type="text/javascript">
  I18n.defaultLocale = 'es_AR';
  I18n.locale = 'es_AR';
  I18n.translations = I18n.translations || {};
  // Spanish (Argentina)
  I18n.translations['es_AR'] = {
    "hello": "Hi {{arg0}}!"
  }
</script>

Finally, it converts message patterns like: Hi {0} into Hi {{arg0}}. This make possible for the I18n JS library to interpolate variables.

string helpers

Functions like abbreviate, capitalize, join, dateFormat, yesno, etc., are available from StringHelpers.

NOTE: You need to register string helpers (they are not added by default)

conditional helpers

Functions like eq, neq, lt, gt, and, or, not, etc., are available from ConditionalHelpers.

NOTE: You need to register conditional helpers (they are not added by default)

TypeSafe Templates

TypeSafe templates are created by extending the TypeSafeTemplate interface. For example:

// 1
public static interface UserTemplate extends TypeSafeTemplate<User> {

  // 2
  public UserTemplate setAge(int age);

  public UserTemplate setRole(String role);

}

// 3
UserTemplate userTmpl = handlebars.compileInline("{{name}} is {{age}} years old!")
  .as(UserTemplate.class);

userTmpl.setAge(32);

assertEquals("Edgar is 32 years old!", userTmpl.apply(new User("Edgar")));
  1. You extend the TypeSafeTemplate interface.
  2. You add all the set method you need. The set method can returns void or TypeSafeTemplate object.
  3. You create a new type safe template using the: as() method.

Registering Helpers

There are two ways of registering helpers.

Using the Helper interface

handlebars.registerHelper("blog", new Helper<Blog>() {
  public CharSequence apply(Blog blog, Options options) {
    return options.fn(blog);
  }
});
handlebars.registerHelper("blog-list", new Helper<List<Blog>>() {
  public CharSequence apply(List<Blog> list, Options options) {
    String ret = "<ul>";
    for (Blog blog: list) {
      ret += "<li>" + options.fn(blog) + "</li>";
    }
    return new Handlebars.SafeString(ret + "</ul>");
  }
});

Using a HelperSource

A helper source is any class with public methods returning an instance of a CharSequence.

  public static? CharSequence methodName(context?, parameter*, options?) {
  }

Where:

  • A method can/can't be static
  • The method's name becomes the helper's name
  • Context, parameters and options are all optionals
  • If context and options are present they must be the first and last arguments of the method

All these are valid definitions of helper methods:

public class HelperSource {
  public String blog(Blog blog, Options options) {
    return options.fn(blog);
  }

  public static String now() {
    return new Date().toString();
  }

  public String render(Blog context, String param0, int param1, boolean param2, Options options) {
    return ...
  }
}

...

handlebars.registerHelpers(new HelperSource());

Or, if you prefer static methods only:

handlebars.registerHelpers(HelperSource.class);

With plain JavaScript

That's right since 1.1.0 you can write helpers in JavaScript:

helpers.js:

Handlebars.registerHelper('hello', function (context) {
 return 'Hello ' + context;
})
handlebars.registerHelpers(new File("helpers.js"));

Cool, isn't?

Helper Options

Parameters

handlebars.registerHelper("blog-list", new Helper<Blog>() {
  public CharSequence apply(List<Blog> list, Options options) {
    String p0 = options.param(0);
    assertEquals("param0", p0);
    Integer p1 = options.param(1);
    assertEquals(123, p1);
    ...
  }
});

Bean bean = new Bean();
bean.setParam1(123);

Template template = handlebars.compileInline("{{#blog-list blogs \"param0\" param1}}{{/blog-list}}");
template.apply(bean);

Default parameters

handlebars.registerHelper("blog-list", new Helper<Blog>() {
  public CharSequence apply(List<Blog> list, Options options) {
    String p0 = options.param(0, "param0");
    assertEquals("param0", p0);
    Integer p1 = options.param(1, 123);
    assertEquals(123, p1);
    ...
  }
});

Template template = handlebars.compileInline("{{#blog-list blogs}}{{/blog-list}}");

Hash

handlebars.registerHelper("blog-list", new Helper<Blog>() {
  public CharSequence apply(List<Blog> list, Options options) {
    String class = options.hash("class");
    assertEquals("blog-css", class);
    ...
  }
});

handlebars.compileInline("{{#blog-list blogs class=\"blog-css\"}}{{/blog-list}}");

Default hash

handlebars.registerHelper("blog-list", new Helper<Blog>() {
  public CharSequence apply(List<Blog> list, Options options) {
    String class = options.hash("class", "blog-css");
    assertEquals("blog-css", class);
    ...
  }
});

handlebars.compileInline("{{#blog-list blogs}}{{/blog-list}}");

Error reporting

Syntax errors

file:line:column: message
   evidence
   ^
[at file:line:column]

Examples:

template.hbs

{{value
/templates.hbs:1:8: found 'eof', expected: 'id', 'parameter', 'hash' or '}'
    {{value
           ^

If a partial isn't found or if it has errors, a call stack is added:

/deep1.hbs:1:5: The partial '/deep2.hbs' could not be found
    {{> deep2
        ^
at /deep1.hbs:1:10
at /deep.hbs:1:10

Helper/Runtime errors

Helper or runtime errors are similar to syntax errors, except for two things:

  1. The location of the problem may (or may not) be the correct one
  2. The stack-trace isn't available

Examples:

Block helper:

public CharSequence apply(final Object context, final Options options) throws IOException {
  if (context == null) {
    throw new IllegalArgumentException(
        "found 'null', expected 'string'");
  }
  if (!(context instanceof String)) {
    throw new IllegalArgumentException(
        "found '" + context + "', expected 'string'");
  }
  ...
}

base.hbs


{{#block}} {{/block}}

Handlebars.java reports:

/base.hbs:2:4: found 'null', expected 'string'
    {{#block}} ... {{/block}}

In short, from a helper you can throw an Exception and Handlebars.java will add the filename, line, column and the evidence.

Advanced Usage

Extending the context stack

Let's say you need to access to the current logged-in user in every single view/page. You can publish the current logged in user by hooking into the context-stack. See it in action:

 hookContextStack(Object model, Template template) {
   User user = ....;// Get the logged-in user from somewhere
   Map moreData = ...;
   Context context = Context
     .newBuilder(model)
       .combine("user", user)
       .combine(moreData)
       .build();
   template.apply(context);
   context.destroy();
 }

Where is the hookContextStack method? Well, it depends on your application architecture.

Using the ValueResolver

By default, Handlebars.java use the JavaBean methods (i.e. public getXxx and isXxx methods) and Map as value resolvers.

You can choose a different value resolver. This section describe how to do this.

The JavaBeanValueResolver

Resolves values from public methods prefixed with "get/is"

Context context = Context
  .newBuilder(model)
  .resolver(JavaBeanValueResolver.INSTANCE)
  .build();

The FieldValueResolver

Resolves values from no-static fields.

Context context = Context
  .newBuilder(model)
  .resolver(FieldValueResolver.INSTANCE)
  .build();

The MapValueResolver

Resolves values from a java.util.Map objects.

Context context = Context
  .newBuilder(model)
  .resolver(MapValueResolver.INSTANCE)
  .build();

The MethodValueResolver

Resolves values from public methods.

Context context = Context
  .newBuilder(model)
  .resolver(MethodValueResolver.INSTANCE)
  .build();

The JsonNodeValueResolver

Resolves values from JsonNode objects.

Context context = Context
  .newBuilder(model)
  .resolver(JsonNodeValueResolver.INSTANCE)
  .build();

Available in Jackson 1.x and Jackson 2.x modules.

Using multiples value resolvers

Context context = Context
  .newBuilder(model)
  .resolver(
      MapValueResolver.INSTANCE,
      JavaBeanValueResolver.INSTANCE,
      FieldValueResolver.INSTANCE
  ).build();

The Cache System

The cache system is designed to provide scalability and flexibility. Here is a quick view of the TemplateCache system:

 public interface TemplateCache {

  /**
   * Remove all mappings from the cache.
   */
  void clear();

  /**
   * Evict the mapping for this source from this cache if it is present.
   *
   * @param source the source whose mapping is to be removed from the cache
   */
  void evict(TemplateSource source);

  /**
   * Return the value to which this cache maps the specified key.
   *
   * @param source source whose associated template is to be returned.
   * @param parser The Handlebars parser.
   * @return A template.
   * @throws IOException If input can't be parsed.
   */
  Template get(TemplateSource source, Parser parser) throws IOException;
}

As you can see, there isn't a put method. All the hard work is done in the get method, which is basically the core of the cache system.

By default, Handlebars.java uses a null cache implementation (a.k.a. no cache at all) which looks like:

Template get(TemplateSource source, Parser parser) throws IOException {
  return parser.parse(source);
}

In addition to the null cache, Handlebars.java provides three more implementations:

  1. ConcurrentMapTemplateCache: a template cache implementation built on top of a ConcurrentMap that detects changes in files automatically. This implementation works very well in general, but there is a small window where two or more threads can compile the same template. This isn't a huge problem with Handlebars.java because the compiler is very very fast. But if for some reason you don't want this, you can use the HighConcurrencyTemplateCache template cache.

  2. HighConcurrencyTemplateCache: a template cache implementation built on top of ConcurrentMap that detects changes in files automatically. This cache implementation eliminates the window created by ConcurrentMapTemplateCache to zero. It follows the patterns described in Java Concurrency in Practice and ensures that a template will be compiled just once regardless of the number of threads.

  3. GuavaTemplateCache: a template cache implementation built on top of Google Guava. Available in handlebars-guava-cache module

You can configure Handlebars.java to use a cache by:

Handlebars hbs = new Handlebars()
  .with(new MyCache());

Using a MissingValueResolver (@deprecated)

NOTE: MissingValueResolver is available in <= 1.3.0. For > 1.3.0 use Helper Missing.

A MissingValueResolver let you use default values for {{variable}} expressions resolved to null.

  MissingValueResolver missingValueResolver = new MissingValueResolver() {
    public String resolve(Object context, String name) {
      //return a default value or throw an exception
      ...;
    }
  };
  Handlebars handlebars = new Handlebars().with(missingValueResolver);

Helper Missing

By default, Handlebars.java throws an java.lang.IllegalArgumentException() if a helper cannot be resolved. You can override the default behaviour by providing a special helper: helperMissing. Example:

  handlebars.registerHelperMissing(new Helper<Object>() {
    @Override
    public CharSequence apply(final Object context, final Options options) throws IOException {
      return options.fn.text();
    }
  });

String form parameters

You can access a parameter name if you set the: stringParams: true. Example:

{{sayHi this edgar}}
  Handlebars handlebars = new Handlebars()
    .stringParams(true);
  
  handlebars.registerHelper("sayHi", new Helper<Object>() {
    public Object apply(Object context, Options options) {
      return "Hello " + options.param(0) + "!";
    }
  });

results in:

Hello edgar!

How does this work? stringParams: true instructs Handlebars.java to resolve a parameter to it's name if the value isn't present in the context stack.

Allow Infinite loops

By default, Handlebars.java doesn't allow a partial to call itself (directly or indirectly). You can change this by setting the: Handlebars.inifiteLoops(true), but watch out for a StackOverflowError.

Pretty Print

The Mustache Spec has some rules for removing spaces and new lines. This feature is disabled by default. You can turn this on by setting the: Handlebars.prettyPrint(true).

Modules

Jackson 1.x

Maven:

 <dependency>
   <groupId>com.github.jknack</groupId>
   <artifactId>handlebars-json</artifactId>
   <version>${handlebars-version}</version>
 </dependency>

Usage:

 handlebars.registerHelper("json", JacksonHelper.INSTANCE);
 {{json context [view="foo.MyFullyQualifiedClassName"] [escapeHTML=false] [pretty=false]}}

Alternative:

 handlebars.registerHelper("json", new JacksonHelper().viewAlias("myView",
   foo.MyFullyQualifiedClassName.class);
 {{json context [view="myView"] [escapeHTML=false] [pretty=false]}}

context: An object, may be null.

view: The name of the Jackson View. Optional.

escapeHTML: True, if the JSON content contains HTML chars and you need to escaped them. Default is: false.

pretty: True, if the JSON content must be formatted. Default is: false.

Jackson 2.x

Maven:

 <dependency>
   <groupId>com.github.jknack</groupId>
   <artifactId>handlebars-jackson2</artifactId>
   <version>${handlebars-version}</version>
 </dependency>

Same as Jackson1.x, except for the name of the helper: Jackson2Helper

Markdown

Maven:

 <dependency>
   <groupId>com.github.jknack</groupId>
   <artifactId>handlebars-markdown</artifactId>
   <version>${handlebars-version}</version>
 </dependency>

Usage:

 handlebars.registerHelper("md", new MarkdownHelper());
 {{md context}}

context: An object or null. Required.

Humanize

Maven:

 <dependency>
   <groupId>com.github.jknack</groupId>
   <artifactId>handlebars-humanize</artifactId>
   <version>${handlebars-version}</version>
 </dependency>

Usage:

 // Register all the humanize helpers.
 HumanizeHelper.register(handlebars);

See the JavaDoc of the [HumanizeHelper] (https://github.com/jknack/handlebars.java/blob/master/handlebars-humanize/src/main/java/com/github/jknack/handlebars/HumanizeHelper.java) for more information.

SpringMVC

Maven:

 <dependency>
   <groupId>com.github.jknack</groupId>
   <artifactId>handlebars-springmvc</artifactId>
   <version>${handlebars-version}</version>
 </dependency>

Using value resolvers:

 HandlebarsViewResolver viewResolver = ...;

 viewResolver.setValueResolvers(...);

In addition, the HandlebarsViewResolver add a message helper that uses the Spring MessageSource class:

{{message "code" [arg]* [default="default message"]}}

where:

  • code: the message's code. Required.
  • arg: the message's argument. Optional.
  • default: the default's message. Optional.

Checkout the HandlebarsViewResolver.

Performance

Handlebars.java is a modern and full featured template engine, but also has a very good performance (Hbs):

Template Comparison

Benchmark source code is available at: https://github.com/mbosecke/template-benchmark

Architecture and API Design

  • Handlebars.java follows the JavaScript API with some minors exceptions due to the nature of the Java language.
  • The parser is built on top of [ANTLR v4] (http://www.antlr.org/).
  • Data is provided as primitive types (int, boolean, double, etc.), strings, maps, list or JavaBeans objects.
  • Helpers are type-safe.
  • Handlebars.java is thread-safe.

Differences between Handlebars.java and Handlebars.js

Handlebars.java scope resolution follows the Mustache Spec. For example:

Given:

{
  "value": "parent",
  "child": {
  }
}

and

Hello {{#child}}{{value}}{{/child}}

will be:

Hello parent

Now, the same model and template with Handlebars.js is:

Hello 

That is because Handlebars.js doesn't look in the context stack for missing attributes in the current scope (this is consistent with the Mustache Spec).

Hopefully, you can turn-off the context stack lookup in Handlebars.java by qualifying the attribute with this.:

Hello {{#child}}{{this.value}}{{/child}}

Differences between Handlebars.java and Mustache.js

  • Handlebars.java throws a java.io.FileNotFoundException if a partial cannot be loaded.

Status

Mustache 1.0 Compliant

Handlebars.js Compliant

Dependencies

+- org.slf4j:slf4j-api:jar:1.6.4

FAQ

Want to contribute?

  • Fork the project on Github.
  • Wondering what to work on? See task/bug list and pick up something you would like to work on.
  • Do you want to donate one or more helpers? See handlebars=helpers a repository for community's helpers.
  • Create an issue or fix one from issues list.
  • If you know the answer to a question posted to our mailing list - don't hesitate to write a reply.
  • Share your ideas or ask questions on mailing list - don't hesitate to write a reply - that helps us improve javadocs/FAQ.
  • If you miss a particular feature - browse or ask on the mailing list - don't hesitate to write a reply, show us some sample code and describe the problem.
  • Write a blog post about how you use or extend handlebars.java.
  • Please suggest changes to javadoc/exception messages when you find something unclear.
  • If you have problems with documentation, find it non intuitive or hard to follow - let us know about it, we'll try to make it better according to your suggestions. Any constructive critique is greatly appreciated. Don't forget that this is an open source project developed and documented in spare time.

Help and Support

Help and discussion

Bugs, Issues and Features

Donate

Buy Edgar a beer!

Related Projects

Author

Edgar Espina

License

Apache License 2

Comments
  • JavaScript helpers support on the server side

    JavaScript helpers support on the server side

    Nashorn

    dynjs

    Currently, there's a disconnect in helper method implementations between client and server when using Handlebars.java in that methods implemented on the client would use JavaScript while methods implemented on the server would use Java.

    While a helper method can be written in both languages, this requires additional maintenance, convention and oversight to accomplish successfully.

    It's not uncommon for shops to have a front end development team who owns the view implementing helper methods in JavaScript, so there is clear value in having the same method exist in both the client and the server to allow full flexibility for rendering content.

    new feature 
    opened by theotherian 33
  • Upgrade commons-text to 1.10.0 due to CVE-2022-42889

    Upgrade commons-text to 1.10.0 due to CVE-2022-42889

    See https://nvd.nist.gov/vuln/detail/CVE-2022-42889

    I tried to build the project locally to see if there were any compatibility issues. I can build and test Handlebars.java, and I can compile but not test the next module Handlebars. Tests fail because I don't have a JDK old enough to support Nashorn (removed in JDK 15).

    bug 
    opened by Ironlink 21
  • Missing helper: 'i18nJs'

    Missing helper: 'i18nJs'

    Hi,

    I am getting this error Missing helper: 'i18nJs' on including {{i18nJs}} in my template.

    Note: i am using maven plugin and i have added i18n.js also.

    enhancement 
    opened by ersubodhgupta 21
  • WARNING: Illegal reflective access by com.github.jknack.handlebars.context.MemberValueResolver

    WARNING: Illegal reflective access by com.github.jknack.handlebars.context.MemberValueResolver

    I've been working on migrating some projects from java 8 to java 11. As I was compiling, I noticed a warning in the log:

    WARNING: An illegal reflective access operation has occurred
    WARNING: Illegal reflective access by com.github.jknack.handlebars.context.MemberValueResolver (../.m2/repository/com/github/jknack/handlebars/4.1.2/handlebars-4.1.2.jar) to method java.util.Collections$EmptyMap.isEmpty()
    WARNING: Please consider reporting this to the maintainers of com.github.jknack.handlebars.context.MemberValueResolver
    WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
    WARNING: All illegal access operations will be denied in a future release
    

    So, I figured I'd create an issue and make sure you're aware. It works with java 11...not sure what will happen with java 12 which should be released March 2019.

    opened by free2bcreative 15
  • EachHelper iterates over Map?

    EachHelper iterates over Map?

    this is probably a corner usage case

    currently handlebars js #each helper supports an array, or an object (associative array).

    EachHelper in handlebars-java takes an Iterable. If i pass in a NativeObject (from Rhino which implements Map interface) to EachHelper, it will not iterate over the keys cuz java Map is not an Iterable.

    wondering if it s gonna be supported in 2.0

    question 
    opened by yoshi95 14
  • Problem with subexpressions

    Problem with subexpressions

    Hello guys,

    I've had some problems with compiling templates that use subexpressions nested in hash. Here's an example of failing template:

    {{#someTemplate param1 param2 hashArg=(myHelper paramX )}}

    The above fails at (myHelper.

    I had a look at your parser implementation and compared it with JavaScript implementatin quickly and i think there is a quick fix for that. Here's your code:

    hash : QID EQ hashValue ;

    hashValue : DOUBLE_STRING #stringHash | SINGLE_STRING #charHash | INT #intHash | BOOLEAN #boolHash | QID #refHash ;

    Here's JS code:

    param : path -> $1 | STRING -> new yy.StringNode($1, @$) | NUMBER -> new yy.NumberNode($1, @$) | BOOLEAN -> new yy.BooleanNode($1, @$) | dataName -> $1 | OPEN_SEXPR sexpr CLOSE_SEXPR {$2.isHelper = true; $$ = $2;} ;

    hash : hashSegment+ -> new yy.HashNode($1, @$) ;

    hashSegment : ID EQUALS param -> [$1, $3] ;

    Do you guys think hashValue could be just param? Or maybe that would work:

    hash : QID EQ param ;

    Sorry, I have no idea about lexers and parsers so I'm just guessing. Please let me know if there is any chance you could fix that in near future. I'll have to make a decision in the company I'm working on based on that.

    Thanks! Chris

    bug 
    opened by ghost 14
  • OSGI dependencies problem

    OSGI dependencies problem

    I'm trying to install a custom handlebars helper on Adobe AEM 6.1, but when I install my bundle which has the dependency

                <dependency>
            <groupId>com.github.jknack</groupId>
            <artifactId>handlebars</artifactId>
            <version>4.0.4</version>
        </dependency> 
    

    then the bundle is unable to go in Active state because it misses a dependency com.github.jknack.handlebars,version=[4.0,5) -- Cannot be resolved

    how can it be possible?

    question 
    opened by francescoferrante 13
  • Dynamic Partials

    Dynamic Partials

    As mentioned in #349, dynamic partials were added to Handlebars.js in wycats/handlebars.js#941. They are invoked using the following syntax.

    {{> (partialNameHelper) }}
    

    In order to use context variables, Handlebars.js uses the lookup helper like this:

    {{> (lookup . 'myVariable') }}
    

    However, the stringFormat helper looks like a viable alternative in Handlebars.java:

    {{> (stringFormat "%s" myVariable) }}
    
    new feature 
    opened by karlhorky 13
  • Improve i18n/locale support

    Improve i18n/locale support

    Unless I'm missing something, there doesn't seem to be a easy way of supporting multiple locales within the same template, which results in needing multiple templates.

    Using Locale.setDefault('xx') in Java is not thread-safe, so not a solution.

    What I'd like ideally would be to have an alternative method signature to template.apply() which accepted a Locale object. e.g. public String apply(Object context, Locale locale)

    question 
    opened by a8cjones 12
  • Syntax when we have space in the JSON key

    Syntax when we have space in the JSON key

    Hi jknack,

    Thank you for your plugin.

    We are trying to get the data of JSON like {{first name}}. You given syntax as {{[first name]}} but this we can't able to implement in our app. Is there any proper solution for this?

    Thanks & Regards, Santosh Kumar

    question 
    opened by santhosh0101 12
  • Only the first line of a partial is indented

    Only the first line of a partial is indented

    I am not sure if I'm doing something wrong or if I have things configured wrong. I'm only seeing the first line of a partial indented, and not subsequent lines. I am a mustache/handlebars noob so it might be possible that I am doing something wrong!

    I have the following in my src/main/resources:

    ./src/main/resources/
    └── handlebar
        └── templates
            ├── child.hbs
            └── parent.hbs
    

    The contents of the files are as follows:

    parent.hbs

    parent line 1
        {{> child}}
    parent line 2
    

    child.hbs

    child line 1
    child line 2
    

    When the template is applied, I see:

    parent line 1
        child line 1
    child line 2
    parent line 2
    

    The code in Java that loads and applies the templates is as follows:

    TemplateLoader loader = new ClassPathTemplateLoader();
    loader.setPrefix("/handlebar/templates");
    loader.setSuffix(".hbs");
    
    Handlebars handlebars = new Handlebars(loader);
    System.out.println(template.apply(null));
    

    The version I am using is 2.2.3 (the latest one in Maven central). I tried this with 2.2.2 and got the same behavior. Thanks!

    bug 
    opened by vivin 12
  • Bump maven-core from 3.8.3 to 3.8.7

    Bump maven-core from 3.8.3 to 3.8.7

    Bumps maven-core from 3.8.3 to 3.8.7.

    Release notes

    Sourced from maven-core's releases.

    3.8.7

    Sub-task

    • [MNG-7019] - Notify also at start when profile is missing

    Bug

    • [MNG-7106] - VersionRange.toString() produces a string that cannot be parsed with VersionRange.createFromVersionSpec() for same lower and upper bounds
    • [MNG-7316] - REGRESSION: MavenProject.getAttachedArtifacts() is read-only
    • [MNG-7352] - org.apache.maven.toolchain.java.JavaToolchainImpl should be public
    • [MNG-7529] - Maven resolver makes bad repository choices when resolving version ranges
    • [MNG-7563] - REGRESSION: User properties now override model properties in dependencies
    • [MNG-7568] - [WARNING] The requested profile "ABCDEF" could not be activated because it does not exist.
    • [MNG-7578] - Building Linux image on Windows impossible (patch incuded)
    • [MNG-7600] - LocalRepositoryManager is created too early
    • [MNG-7621] - Parameter '-f' causes ignoring any 'maven.config' (only on Windows)
    • [MNG-7637] - Possible NPE in MavenProject#hashCode()
    • [MNG-7644] - Fix version comparison where .X1 < -X2 for any string qualifier X

    Improvement

    • [MNG-7590] - Allow configure resolver by properties in settings.xml
    • [MNG-7645] - Implement some #toString() methods

    Task

    • [MNG-7513] - Address commons-io_commons-io vulnerability found in maven latest version
    • [MNG-7634] - Revert MNG-5982 and MNG-7417
    • [MNG-7636] - Partially revert MNG-5868 to restore backward compatibility (see MNG-7316)

    Dependency upgrade

    • [MNG-7506] - Upgrade Maven Wagon to 3.5.2
    • [MNG-7641] - Upgrade Maven Wagon to 3.5.3

    3.8.6

    What's Changed

    Full Changelog: https://github.com/apache/maven/compare/maven-3.8.5...maven-3.8.6

    ... (truncated)

    Commits
    • b89d595 [maven-release-plugin] prepare release maven-3.8.7
    • 6e8b4ff [MNG-7352] org.apache.maven.toolchain.java.JavaToolchainImpl should be public
    • 91ddc37 [MNG-7641] Upgrade Maven Wagon to 3.5.3
    • da4246a [MNG-7644] Fix version comparison where .X1 < -X2 for any string qualifier X
    • 7d45894 Update bundled license for SLF4J
    • ba058ee [MNG-7513] Address commons-io_commons-io vulnerability found in maven latest ...
    • 7db942b [MNG-7634] Revert MNG-5982 and MNG-7417
    • 61f1f01 [MNG-7590] Allow to configure resolver by properties in settings.xml
    • 8fd8a05 [MNG-7600] LocalRepositoryManager is created too early
    • ed84933 [MNG-7506] Upgrade Maven Wagon to 3.5.2
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump maven-plugin-api from 3.8.3 to 3.8.7

    Bump maven-plugin-api from 3.8.3 to 3.8.7

    Bumps maven-plugin-api from 3.8.3 to 3.8.7.

    Release notes

    Sourced from maven-plugin-api's releases.

    3.8.7

    Sub-task

    • [MNG-7019] - Notify also at start when profile is missing

    Bug

    • [MNG-7106] - VersionRange.toString() produces a string that cannot be parsed with VersionRange.createFromVersionSpec() for same lower and upper bounds
    • [MNG-7316] - REGRESSION: MavenProject.getAttachedArtifacts() is read-only
    • [MNG-7352] - org.apache.maven.toolchain.java.JavaToolchainImpl should be public
    • [MNG-7529] - Maven resolver makes bad repository choices when resolving version ranges
    • [MNG-7563] - REGRESSION: User properties now override model properties in dependencies
    • [MNG-7568] - [WARNING] The requested profile "ABCDEF" could not be activated because it does not exist.
    • [MNG-7578] - Building Linux image on Windows impossible (patch incuded)
    • [MNG-7600] - LocalRepositoryManager is created too early
    • [MNG-7621] - Parameter '-f' causes ignoring any 'maven.config' (only on Windows)
    • [MNG-7637] - Possible NPE in MavenProject#hashCode()
    • [MNG-7644] - Fix version comparison where .X1 < -X2 for any string qualifier X

    Improvement

    • [MNG-7590] - Allow configure resolver by properties in settings.xml
    • [MNG-7645] - Implement some #toString() methods

    Task

    • [MNG-7513] - Address commons-io_commons-io vulnerability found in maven latest version
    • [MNG-7634] - Revert MNG-5982 and MNG-7417
    • [MNG-7636] - Partially revert MNG-5868 to restore backward compatibility (see MNG-7316)

    Dependency upgrade

    • [MNG-7506] - Upgrade Maven Wagon to 3.5.2
    • [MNG-7641] - Upgrade Maven Wagon to 3.5.3

    3.8.6

    What's Changed

    Full Changelog: https://github.com/apache/maven/compare/maven-3.8.5...maven-3.8.6

    ... (truncated)

    Commits
    • b89d595 [maven-release-plugin] prepare release maven-3.8.7
    • 6e8b4ff [MNG-7352] org.apache.maven.toolchain.java.JavaToolchainImpl should be public
    • 91ddc37 [MNG-7641] Upgrade Maven Wagon to 3.5.3
    • da4246a [MNG-7644] Fix version comparison where .X1 < -X2 for any string qualifier X
    • 7d45894 Update bundled license for SLF4J
    • ba058ee [MNG-7513] Address commons-io_commons-io vulnerability found in maven latest ...
    • 7db942b [MNG-7634] Revert MNG-5982 and MNG-7417
    • 61f1f01 [MNG-7590] Allow to configure resolver by properties in settings.xml
    • 8fd8a05 [MNG-7600] LocalRepositoryManager is created too early
    • ed84933 [MNG-7506] Upgrade Maven Wagon to 3.5.2
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump slf4j-api from 1.7.32 to 2.0.6

    Bump slf4j-api from 1.7.32 to 2.0.6

    Bumps slf4j-api from 1.7.32 to 2.0.6.

    Commits
    • 5ff6f2c prepare for release 2.0.6
    • 2f4aa75 fix SLF4J-575
    • 363f0a5 remove unused parts
    • 171679b SLF4J-574: Add full OSGi headers, especially "uses" clauses
    • 921b5b3 fix FUNDING file
    • e02244c fix FUNDING file
    • 441d458 fix FUNDING file
    • f5e741b add FUNDING file
    • 2e71327 remove unused log4j dependency in the version definition section of pom.xml
    • 3ff2a30 start work on 2.0.6-SNAPSHOT
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Setting default `ValueResolvers` for non `Context`

    Setting default `ValueResolvers` for non `Context`

    It would be useful to be able to set per Handlebars instance the default ValueResolvers that would be used for any context object passed to apply that isn't already a Context. It seems to be hardcoded for now.

    opened by segevfiner 0
  • `ValueResolver` for kotlinx.serialization and Moshi

    `ValueResolver` for kotlinx.serialization and Moshi

    Similar to the Jackson ones, it would be nice to have a ValueResolver for those serialization libraries. I had to add .content in many places that have a kotlinx.serialization JsonLiteral which inconvenient.

    opened by segevfiner 0
  • `lookup` is not implemented correctly

    `lookup` is not implemented correctly

    lookup is supposed to search for the key literal value, but stuff like dots in it takes effect:

    {
        "foo.js": {
    
        }
    }
    
    {{lookup . "foo.js"}}
    

    Fails while it should work.

    While:

    {{lookup . "[foo.js]"}}
    

    Does work, but that's not how lookup in handlebars.js behaves.

    I'm also not sure about the behavior in the case of a key that is not found.

    opened by segevfiner 1
Releases(v4.3.1)
  • v4.3.1(Oct 18, 2022)

    What's Changed

    • GH-1009: update Apache Commons Text to 1.10.0 (Fix CVE-2022-42889) by @aschwarte10 in https://github.com/jknack/handlebars.java/pull/1010
    • Bump jackson-databind from 2.13.0 to 2.13.2.1 by @dependabot in https://github.com/jknack/handlebars.java/pull/1011
    • Bump snakeyaml from 1.29 to 1.31 by @dependabot in https://github.com/jknack/handlebars.java/pull/1013
    • Bump spring-webmvc from 5.3.10 to 5.3.23 by @dependabot in https://github.com/jknack/handlebars.java/pull/999
    • Bump logback-classic from 1.2.6 to 1.4.4 by @dependabot in https://github.com/jknack/handlebars.java/pull/1005
    • Bump mockito-core from 4.0.0 to 4.8.0 by @dependabot in https://github.com/jknack/handlebars.java/pull/998
    • Bump antlr-version from 4.9.2 to 4.9.3 by @dependabot in https://github.com/jknack/handlebars.java/pull/918
    • Bump jetty-webapp from 9.4.43.v20210629 to 9.4.44.v20210927 in /handlebars-proto by @dependabot in https://github.com/jknack/handlebars.java/pull/1014
    • Bump joda-time from 2.10.12 to 2.12.0 by @dependabot in https://github.com/jknack/handlebars.java/pull/1008

    New Contributors

    • @aschwarte10 made their first contribution in https://github.com/jknack/handlebars.java/pull/1010

    Full Changelog: https://github.com/jknack/handlebars.java/compare/v4.3.0...v4.3.1

    Support my work

    Source code(tar.gz)
    Source code(zip)
  • v4.3.0(Oct 12, 2021)

  • v4.2.1(Sep 26, 2021)

  • v4.2.0(Apr 25, 2020)

  • v4.1.2(Oct 30, 2018)

    Minor release with a regression fix for partials:

    #660 Partial call with line breaks between hash parameters cause exception since version 4.1.1

    #654 Specifying a context resolver without a MapValueResolver breaks list psudo-variables

    Thanks all.

    Source code(tar.gz)
    Source code(zip)
  • v4.1.1(Oct 29, 2018)

    bugs

    #646 IndexOutOfBoundException in Formatter chain #655 Fix inline partial leak

    enhancements

    #656 Control characters aren't allowed in handlebars expressions #657 Literals such as "let", "const" not supported anymore in registerHelpers() API. #643 "empty" variable name does not work in a partial

    Checkout the complete list of changes here

    support

    Please star/follow handlebars.java on Github.

    Buy Edgar a beer!

    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(Jun 11, 2018)

    Great news for Handlebras.java!! This new release is targeted to run Java 8 (finally!) or higher and uses Nashorn as Java Script Engine (removing the need of adding rhino to your classpath).

    New Features

    #569 #626 : Nashorn #625 Java 8 upgrade #633 Standalone jar

    At the same time these changes introduced breaking changes, which are described here:

    dependencies removal

    • Rhino
    • commons-lang3
    • antlr4-runtime

    If your project transitively/indirect uses any of these libraries you must to add them manually to your project.

    Checkout the complete list of changes here

    happy handlebars.java user?

    Please star/follow handlebars.java on Github.

    super happy?

    Buy Edgar a beer!

    Thanks!!

    Source code(tar.gz)
    Source code(zip)
  • v4.0.7(May 29, 2018)

    Happy to announce a new Handelbars.java release!!!

    There are lot lot of small enhancements and bugs fixed!

    Most notable are:

    • #627: Conditional helpers
    • #588: Performance improvements for partials
    • #573: Support decimal formats as helper arguments

    Checkout the complete list of changes here

    happy handlebars.java user?

    Please star/follow handlebars.java on Github.

    super happy?

    Buy Edgar a beer!

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Mar 10, 2014)

Owner
Edgar Espina
Software engineer. Author of https://jooby.io , Handlebars.java and others
Edgar Espina
Cadence is a distributed, scalable, durable, and highly available orchestration engine to execute asynchronous long-running business logic in a scalable and resilient way.

Cadence This repo contains the source code of the Cadence server and other tooling including CLI, schema tools, bench and canary. You can implement yo

Uber Open Source 6.5k Jan 4, 2023
一个基于vue3.0+antd+less+spring boot +mybatis+mysql+maven基础权限管理平台

cc-project vue 版本 angular版本请到 https://github.com/myopenresources/cc-project 这里看 详细文档 请到 cc-project详细文档 介绍 cc-project-vue 是一个前后端分离的项目,前端使用的是vue3.0,后端使用

河马开源-hippo 21 Jun 23, 2022
Tuya 37 Dec 26, 2022
Simulates FGO combat logic (only ally)

FGO模拟器 制作自定义单位时,请主要依照FGO的逻辑来写。 虽然可以写出FGO没有的从者、礼装,但是除非符合逻辑否则程序会做什么我也不知道。 另外这个小程序没有任何联网功能,我也不准备录入所有东西的数据,所以请自己制作需要的部件~ 未来大概就只在github随缘更新,但是现有的制作器基本支持写出绝

Yome 24 Dec 19, 2022
ActiveJ is an alternative Java platform built from the ground up. ActiveJ redefines web, high load, and cloud programming in Java, featuring ultimate performance and scalability!

Introduction ActiveJ is a full-featured modern Java platform, created from the ground up as an alternative to Spring/Micronauts/Netty/Jetty. It is des

ActiveJ LLC 579 Jan 7, 2023
Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based system

FRC 2022 Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based s

null 4 Oct 4, 2022
"Some" Utilities you can use for your Java projects "freely"! Files are compiled with Java-8 and above, but mostly Java-11.

✨ Java-SomeUtils ?? "Some" Utilities you can use for your Java projects "freely"! *"Freely"* forcing you to include the license into your program. Fil

JumperBot_ 2 Jan 6, 2023
The Apache Software Foundation 605 Dec 30, 2022
A suite of software tools and services created to support activity planning and sequencing needs of missions with modeling, simulation, scheduling and validation capabilities

Aerie A suite of software tools and services created to support activity planning and sequencing needs of missions with modeling, simulation, scheduli

NASA Advanced Multi-Mission Operations System 31 Jan 3, 2023
A compact and highly efficient workflow and Business Process Management (BPM) platform for developers, system admins and business users.

Flowable (V6) Maven Central: Docker Images: License: Homepage: https://www.flowable.org/ flowable / flowəb(ə)l / a compact and highly efficient workfl

Flowable 6k Jan 7, 2023
InterfaceMaker is a modern plugin to handle and customize join items, hotbars and menus with a developer and administrator friendly API.

Interface Maker InterfaceMaker is a modern plugin to handle and customize join items, hotbars and menus with a developer friendly API. Features Simple

2LStudios - Minecraft 10 Nov 27, 2022
Program that allows employees to clock in and clock out of work. Employees who are managers can add, edit and delete employees and shifts from the database.

Clock-In-Clock-Out-System Created by: Kennedy Janto, Taylor Vandenberg, Duc Nguyen, Alex Gomez, Janista Gitbumrungsin This is a semester long project

null 6 Nov 5, 2022
This repository contains the code for the Runescape private server project, and this repo is soley maintained by @Avanae and @ThePolyphia and @Xeveral

Runescape: The private server project. A Runescape private server based on the 2009 era. This repository contains the code for the Runescape private s

ProjectArchitecture 4 Oct 1, 2022
Plugin for Spigot, PaperMC, BungeeCord and Velocity to create custom MOTDs, playercount message and playercount hover with priorities and conditions.

AdvancedServerList AdvancedServerList is a server and proxy plugin that allows you to create custom MOTDs and more in your server list with priority a

Andre_601 19 Dec 14, 2022
An Open-Source repository 🌎 that contains all the Data Structures and Algorithms concepts and their implementation, programming questions and Interview questions

An Open-Source repository ?? that contains all the Data Structures and Algorithms concepts and their implementation, programming questions and Interview questions. The main aim of this repository is to help students who are learning Data Structures and Algorithms or preparing for an interview.

Aritra Das 19 Dec 29, 2022
A factory and generators framework for Java 7 and up.

Factorium-J7 A simple generator and factory framework. Compatibility Compatibility is guaranteed for Java 7 and up. How to use it The core interfaces

Samuel Beausoleil 0 Jul 20, 2022
A library to create, read and validate ZUGFeRD compliant invoices. Available for Java and .NET

Konik ZUGFeRD Library Is an easy to use open source implementation of the ZUGFeRD data model including various enhancements. Features Easy and underst

Konik 42 Dec 20, 2022
The goal of the project is to create a web application using Java EE and database (PostgreSQL) without connecting a modern technology stack like spring boot and hibernate

About The Project SignIn page SignUp page Profile page The goal of the project is to create a web application using Java EE and database (PostgreSQL)

Islam Khabibullin 2 Mar 23, 2022