Sinobu is not obsolete framework but utility, which can manipulate objects as a extremely-condensed facade. This is extremely lightweight at approximately 120 KB without relying on other libraries, and its various operations are designed to run as fast as other competing libraries.
This library aims to simplify and highly condense the functions related to domains that are frequently encountered in real-world development projects, making them easier to use.
- Dependency Injection
- Object lifecycle management
- Property based object modeling
- HTTP(S) Client
- Web Socket Client
- JSON
- HTML (including Tag Soup)
- XML
- Reactive Programming (Rx)
- Asynchronous & Parallel processing
- Multilingualization
- Template Engine (Mustache)
- Dynamic plug-in mechanism
- Object Persistence
- Logging (Garbage-Free)
- Virtual Job Scheduler
- Cron Scheduling
With a few exceptions, Sinobu and its APIs are designed to be simple to use and easy to understand by adhering to the following principles.
- Keep it stupid simple
- Less is more
- Type safety
- Refactoring safety
Create instant from type.
class Some {
}
assert I.make(Some.class) != I.make(Some.class);
Create singleton instance. (managed lifestyle)
@Managed(Singleton.class)
class Some {
}
assert I.make(Some.class) == I.make(Some.class);
Enable dependency injection without configuration. (constructor injection)
class Injected {
}
class Injectable {
Injected injected;
Injectable(Injected injected) {
this.injected = injected;
}
}
Injectable Injectable = I.make(Injectable.class);
assert Injectable.injected != null;
Read contents from HTTP.
I.http("https://httpstat.us/200", String.class).to(text -> {
// read as text
});
I.http("https://httpstat.us/200", JSON.class).to(json -> {
// read as JSON
});
I.http("https://httpstat.us/200", XML.class).to(xml -> {
// read as XML
});
Parse JSON.
JSON json = I.json("""
{
"name": "忍",
"age": 598
}
""");
// read value as String (shorthand)
assert json.text("name").equals("忍");
// read value as int
assert json.get("age").as(int.class) == 598;
Parse XML/HTML. (accept tag soup)
XML html = I.xml("""
<html>
<body>
<h1>Heading</h1>
<div class="age">598</div>
<p>contents</p>
<div class="author">忍</p>
</body>
</html>
""");
// select the element by CSS selector and read its text content
assert html.find("p").text().equals("contents");
assert html.find(".author").text().equals("忍");
Reactive stream. (Rx)
String result = I.signal("This", "is", "reactive", "stream")
.skip(2)
.map(String::toUpperCase)
.scan(Collectors.joining(" "))
.to()
.exact();
assert result.equals("REACTIVE STREAM");
Evaluate expression language. (Mustache-like syntax)
Person person = new Person();
person.name = "忍";
person.age = 598;
assert I.express("{name} is {age} years old.", person).equals("忍 is 598 years old.");
Write log message on console, file and user-defined appender.
I.trace("Default logging level is INFO.");
I.debug("your.logger.name", "Different logger names can be used for different output settings.");
I.info("system", "The default logger name is [system].");
I.warn("""
The following settings can be changed for each logger:
* log level
* displying caller location
* output directory of log file
* whether the log file is overwritten or appended
* the number of days the log file is kept
""");
I.error((Supplier) () -> "Use a lambda expression to delay message building.");