Project List
Fairfax Media
Pocketbook
Red Unicorn
Agin3
Project Name | Short Description | Still Involved? | Started in |
---|---|---|---|
mQlicker | Audience Response System |
✔ Yes
|
2010 |
Personal (Open Source)
Project Name | Short Description | Still Involved? | Started in |
---|---|---|---|
Test0ster1 (Testosterone) | Test Helper Framework using Java 8's Functional Features |
✔ Yes
|
2014 |
J8Plus | Library for Java 8 - Tail Call Recursion in Java 8 / Useful Tools using Higher-Order Functions |
✔ Yes
|
2014 |
Skala | Small Tool for Scala |
✔ Yes
|
2015 |
JSON Statham | Java / JSON mapping library |
✔ Yes
|
2009 |
KommonLee | Commonly used reusable Java libraries |
✔ Yes
|
2009 |
Web Method | Web method description exposure library |
✔ Yes
|
2010 |
Trac Issues to GitLab | Migration tool: Trac issue tickets => GitLab issues |
✔ Yes
|
2013 |
Example Web Applications | Example Web Applications with live demo |
✔ Yes
|
2013 |
Maven Plugins | Maven Plugins |
✔ Yes
|
2013 |
Elixirian
Project Name | Short Description | Still Involved? | Started in |
---|---|---|---|
iSAM | International Student Agency Manager |
No
|
2009/2012 |
Alkuhmee | Unified Web APIs for handling many CRUD actions at once |
No
|
2012 |
UTS
Project Name | Short Description | Still Involved? | Started in |
---|---|---|---|
TeCTra | Team Contribution Tracking System | No |
2007 |
Company: Fairfax Media
Site: Fairfax Media
Company: Fairfax Media
- Development of media platform using Scala and Akka Framework
- Writing test and documents for Scala application
- Writing Akka Persistence Plugin for Redis
- CI & CD: Automatic build and deployment to AWS
Company: Pocketbook
Pocketbook
Site: Pocketbook
Company: Pocketbook Pty Ltd
- Development of Java web application and web API
- Refactoring and optimizing the existing code.
- Improving performance and code quality using Lambda expressions and Stream API in Java 8
- Development of iOS and Android Apps
- Setting up Development Environment (including migration from SVN to Git)
Company: Red Unicorn
- Development of Java web API platform and web applications:
- Using Spring MVC, Hibernate, Morphia, MS SQL server, MongoDB, Ajax, etc.
Company: Agin3
mQlicker
Site: http://www.mqlicker.com
Company: Agin3 Pty Ltd
mQlicker [pronounced as "m clicker"] is an audience response system, which I’ve been developing for about two plus years. It is now being used by universities, high schools, other educational institutions and companies in the US, Europe, Australia and several Asian counties. There are two programmers, including myself, working on the project.
I’ve been doing the sever-side development using well known frameworks and libraries as well as my own ones. The other developer is responsible for the client-side web application development using JavaScript and JavaScript frameworks & libraries.
We focused on collaboration and increasing productivity so have made a library which describes the available functions in the server-side so that the client-side developer can easily work on the available ones. Thus, even though we work remotely, there is no problem or any decrease in productivity. My colleague has been overseas for about one year, yet we can easily and quickly fix bugs and add new features. The application has been built and tested more than 1900 times using the continuous integration tool, Jenkins with Maven.
Personal (Open Source)
Test0ster1 (Open source)
Site: https://github.com/Kevin-Lee/test0ster1
Source:
Test0ster1 (pronounced as 'Testosterone', Testosterone -> Test0sterone -> Test0ster(one == 1) -> Test0ster1 ) is a simple test helper framework which uses Java 8's new functional features (i.e. Lambda Expressions, Default Methods, etc.) in order to provide simple and easy to use test tools.
@Test public void testNullSafeTrim() { final String expected = "result"; final String input = " " + expected + " "; test("assertThat", "nullSafeTrim(\" result \") should return \"result\".") .when(() -> nullSafeTrim(input) ) .then(actual -> assertThat(actual.length()).isEqualTo(expected.length()) ) .then(actual -> { assertThat(actual).isEqualTo(expected); }); }
@Test public void testClosure() { /* given */ final Runnable innerRunnable1 = mock(Runnable.class); final Runnable innerRunnable2 = mock(Runnable.class); final Runnable runnable = () -> { innerRunnable1.run(); innerRunnable2.run(); }; test("verifyVoidMethod", "innerRunnable1.run() and innerRunnable2.run() should be invoked when runnable.run().") .when(() -> { runnable.run(); }) .then(() -> verify(innerRunnable1, times(1)).run() ) .then(() -> { verify(innerRunnable2, times(1)).run(); }); }
@Test public void testExpectedException() { final String value = null; test("throwingNullTest", "Objects.requireNonNull(null, \"message\") should throw NullPointerException.") .when(() -> { Objects.requireNonNull(value, "value cannot be null."); }) .expect(throwing(NullPointerException.class) .containsMessage("cannot be null")); }
J8+ (Open source)
Site: https://github.com/Kevin-Lee/j8plus
Source:
J8+ (J8Plus) is a library for Java 8 - Tail Call Recursion in Java 8 / Useful Tools using Higher-Order Functions / Additional Functions with Currying available and so on.
// From: the code may cause a stack overflow exception. public static BigInteger factorial(final BigInteger acc, final BigInteger n) { if (n.equals(BigInteger.ONE)) { return acc; } return factorial(acc.multiply(n), n.subtract(BigInteger.ONE)); } // To: tail call optimized public static TailCallable<BigInteger> factorial(final BigInteger acc, final BigInteger n) { if (n.equals(BigInteger.ONE)) { return done(acc); } return () -> factorial(acc.multiply(n), n.subtract(BigInteger.ONE)); }
Because Java API does not normally provide opposite operation, it is not possible to use method reference to filter out values easily.
e.g.) Current Java API does not let you use method reference to keep only non empty String values.
List<String> nonEmptyStrings = list.stream() .filter(text -> !text.isEmpty()) .collect(toList()) // Yet, J8+ can give it to you! List<String> nonEmptyStrings = list.stream() .filter(not(String::isEmpty)) .collect(toList())
Not a surpise! currying is not supported by the Java language even by Java 8!
Java 8's BiFunctional interfaces do not have a method to support it either, but again, J8+ is here for you to support currying!
final Function3<Integer, Integer, Integer, Integer> addThreeNumbers = (a, b, c) -> a + b + c; final Function<Integer, Integer> onePlusTwo = addThreeNumbers.curried(1).curried(2); final int result1 = onePlusTwo.apply(3); // 1 + 2 + 3 = 6 final int result2 = onePlusTwo.apply(7); // 1 + 2 + 7 = 10
Skala (Open source)
Site: https://github.com/Kevin-Lee/skala
Source:
Skala is a small utility library for Scala.
tryWith(AutoCloseable) { autoCloseable => // run block } val result = tryWith(AutoCloseable) { autoCloseable => // run block } tryWith(new FileInputStream("/path/to/file.txt")) { inputStream => var c = inputStream.read() while (c != -1) { print(c.asInstanceOf[Char]) c = inputStream.read() } } tryWith(new FileInputStream("/path/to/file.txt")) { inputStream => tryWith(new InputStreamReader(inputStream)) { reader => var c = reader.read() while (c != -1) { print(c.asInstanceOf[Char]) c = reader.read() } } } val result = tryWith(new SomeResource()) { someSource => someSource.get }
It returns Option
may or may not have a square root of a BigDecimal
value. This method doesn't throw any exception when a negative number is passed as a parameter. Instead, it returns None
.
import io.kevinlee.skala.math.BigDecimals._ findSqrt(BigDecimal(9)) // Result: Some(BigDecimal(3)) findSqrt(BigDecimal(10)) // Result: Some(BigDecimal(3.162277660168379331998893544432718)) findSqrt(BigDecimal(-1)) // Result: None
It calculates a mean of TraversableLike[BigDecimal, TraversableLike[BigDecimal, _]]
import io.kevinlee.skala.math.BigDecimals._ val numbers = List[BigDecimal](1, 2, 3) mean(numbers) // returns BigDecimal(2)
It finds a median of Seq[BigDecimal]
.
import io.kevinlee.skala.math.BigDecimals._ val numbers = List[BigDecimal](1, 2, 3, 4) median(numbers) // return BigDecimal(2.5) val numbers2 = List[BigDecimal](2, 4, 3, 1) median(numbers2) // return BigDecimal(2.5) val numbers3 = List[BigDecimal](1, 2, 3, 4, 5) median(numbers3) // return BigDecimal(3) val numbers4 = List[BigDecimal](2, 3, 5, 4, 1) median(numbers4) // return BigDecimal(3)
JSON Statham (Open source)
JSON Statham is a Java JSON Mapping library, written all by myself, to help any Java application development that requires use of JSON. It provides an easy way to convert Java object into JSON and JSON into Java object without sacrificing immutability. It is used and tested by mQlicker and iSAM development and is being evolved. This library also works well with the Spring framework so if the front-end sends a JSON object as a parameter value, Spring can automatically convert it into a Java object using JSON Statham.
Java to JSON
import org.elixirian.jsonstatham.annotation.Json; import org.elixirian.jsonstatham.annotation.JsonField; @Json public class Pojo { @JsonField private final Long id; @JsonField private final String name; @JsonField private final String address; public Pojo(final Long id, final String name, final String address) { this.id = id; this.name = name; this.address = address; } public Long getId() { return id; } public String getName() { return name; } public String getAddress() { return address; } // remainder omitted... }
final Pojo pojo = new Pojo(5, "Kevin Lee", "123 ABC Street"); final String result = jsonStatham.convertIntoJson(pojo); System.out.println(result);
Result
{ "id":5, "name":"Kevin Lee", "address":"123 ABC Street" }
JSON to Java
{ "id":5, "name":"Kevin Lee", "address":"123 ABC Street" }
final String json = "{\"id\":5,\"name\":\"Kevin Lee\",\"address\":\"123 ABC Street\"}"; final Pojo pojo = jsonStatham.convertFromJson(Pojo.class, json); System.out.println("id: " + pojo.getId()); System.out.println("name: " + pojo.getName()); System.out.println("address: " + pojo.getAddress());
Result
id: 5 name: Kevin Lee address: 123 ABC Street
import java.math.BigDecimal; import java.math.BigInteger; import org.elixirian.jsonstatham.annotation.Json; import org.elixirian.jsonstatham.annotation.JsonField; @Json public class Product { @JsonField private final Long id; @JsonField private final String name; @JsonField private final BigDecimal price; @JsonField private final BigInteger quantity; public Product(final Long id, final String name, final BigDecimal price, final BigInteger quantity) { this.id = id; this.name = name; this.price = price; this.quantity = quantity; } // remainder omitted... }
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping("/product-management") public class ProductController { @RequestMapping(method = { RequestMethod.POST }, value = "/add/product") public ModelAndView modifyInteraction(@RequestParam final Product product) { // your code here... } @RequestMapping(method = { RequestMethod.POST }, value = "/add/products") public ModelAndView modifyInteraction(@RequestParam final Product[] products) { // your code here... } }
KommonLee (Open source)
Source:
Test | Core | ASM | Web | Web3 |
---|---|---|---|---|
KommonLee is a set of commonly used reusable Java libraries, written by myself, in order to ease Java programming. It offers convenient and reusable APIs so that the users of this library can enjoy coding and focus on solving the actual problems rather than dealing with annoying APIs and missing features in the Java programming language. The library is well tested and most elements in the project have over 90% test coverage. I have even built a test tool to test a private constructor in order to get higher test coverage to make the library more solid.
import static org.elixirian.kommonlee.util.Objects.*; public class FileElement { // ... @Override public int hashCode() { return hash(folder, name); } @Override public boolean equals(final Object fileElement) { if (this == fileElement) { return true; } final FileElement that = castIfInstanceOf(FileElement.class, fileElement); return null != that && (equal(this.folder, that.getFolder()) && equal(this.name, that.getName())); } }
import static org.elixirian.kommonlee.util.Objects.*; //... @Override public String toString() { return toStringBuilder(this) .add("id", id) .add("folder", folder) .add("name", name) .toString(); }
import static org.elixirian.kommonlee.util.collect.Lists.*; import static org.elixirian.kommonlee.util.collect.Sets.*; import java.util.List; import java.util.Set; // ... final List<Integer> integerList = newArrayList(); final List<Integer> integerList2 = newArrayList(-14, -10, -1, 0, 1, 2, 10, 35, 100); final Set<Integer> integerSet = newHashSet(); final Set<Integer> integerSet2 = newHashSet(-14, -10, -1, 0, 1, 2, 10, 35, 100);
import static org.elixirian.kommonlee.io.IoCommonConstants.*; import static org.elixirian.kommonlee.io.util.IoUtil.*; import java.io.File; import java.io.IOException; import org.elixirian.kommonlee.io.ByteArrayConsumer; //... final StringBuilder stringBuilder = new StringBuilder(); final File file = new File("/tmp/test.txt"); readFile(file, BUFFER_SIZE_128Ki, new ByteArrayConsumer() { @Override public void consume(final byte[] bytes, final int offset, final int count) throws IOException { stringBuilder.append(new String(bytes, offset, count)); } }); System.out.println(stringBuilder);Or
import static org.elixirian.kommonlee.io.DataConsumers.*; import static org.elixirian.kommonlee.io.IoCommonConstants.*; import static org.elixirian.kommonlee.io.util.IoUtil.*; import java.io.File; import java.io.IOException; import org.elixirian.kommonlee.io.ByteArrayConsumingContainer; //... final File file = new File("/tmp/test.txt"); final ByteArrayConsumingContainer byteArrayConsumingContainer = newByteArrayConsumingContainer(); readFile(file, BUFFER_SIZE_128Ki, byteArrayConsumingContainer); System.out.println(byteArrayConsumingContainer.toString());
import static org.elixirian.kommonlee.collect.immutable.ImmutableLists.*; import org.elixirian.kommonlee.collect.immutable.ImmutableList; import java.util.Set; // ... final ImmutableList<Integer> list = listOf(-14, -10, -1, 0, 1, 2, 10, 35, 100);
import static org.elixirian.kommonlee.collect.immutable.ImmutableLists.*; import org.elixirian.kommonlee.collect.immutable.ImmutableList; import org.elixirian.kommonlee.type.functional.Condition1; // ... final ImmutableList<Integer> list = listOf(-14, -10, -1, 0, 1, 2, 10, 35, 100) .select(new Condition1<Integer>() { @Override public boolean isMet(final Integer integer) { return integer.intValue() > 0; } });If you use JDK8,
import static org.elixirian.kommonlee.collect.immutable.ImmutableLists.*; import org.elixirian.kommonlee.collect.immutable.ImmutableList; // ... final ImmutableList<Integer> list = listOf(-14, -10, -1, 0, 1, 2, 10, 35, 100) .select(integer -> integer.intValue() > 0);
import static org.elixirian.kommonlee.functional.collect.CollectionUtil.*; import static org.elixirian.kommonlee.util.collect.Lists.*; // ... final List<Integer> integerList = newArrayList(-100, -55, -32, -21, -17, -10, -3, 0, 1, 15, 33, 77, 999, 1234); final Condition1<Integer> positiveInteger = new Condition1<Integer>() { @Override public boolean isMet(final Integer integer) { return 0 < integer.intValue(); } }; final List<Integer> positiveIntegerList = selector() .fromIterable() .toArrayList() .select(integerList, positiveInteger); System.out.println("positiveIntegerList: " + positiveIntegerList);With JDK8,
import static org.elixirian.kommonlee.functional.collect.CollectionUtil.*; import static org.elixirian.kommonlee.util.collect.Lists.*; // ... final List<Integer> integerList = newArrayList(-100, -55, -32, -21, -17, -10, -3, 0, 1, 15, 33, 77, 999, 1234); final List<Integer> positiveIntegerList = selector() .fromIterable() .toArrayList() .select(integerList, i -> i > 0); System.out.println("positiveIntegerList: " + positiveIntegerList);
final List<Person> personList = newArrayList(new Person("Lee", "Kevin", "test@test.email.com"), new Person("Kent", "Clark", "clark.kent@krypton.com"), new Person("Wayne", "Bruce", "bruce.wayne@gotham.com"), new Person("Lee", "Tom", "test@another.test-email.com"), new Person("Odinson", "Thor", "thor.odinson@asgard.com"), new Person("Stark","Tony", "tony.stark@stark.com")); // reusable mapper function final Function1<Person, String> personToEmailMapper = new Function1<Person, String>() { @Override public String apply(final Person person) { return person.getEmail(); } }; final List<String> emailAddressList = mapper() .fromIterable() .toArrayList() .map(personList, personToEmailMapper); System.out.println("emailAddressList: " + emailAddressList); final Set<String> emailAddressSet = mapper() .fromIterable() .toHashSet() .map(personList, personToEmailMapper); System.out.println("emailAddressSet: " + emailAddressSet);With JDK8,
final List<Person> personList = newArrayList(new Person("Lee", "Kevin", "test@test.email.com"), new Person("Kent", "Clark", "clark.kent@krypton.com"), new Person("Wayne", "Bruce", "bruce.wayne@gotham.com"), new Person("Lee", "Tom", "test@another.test-email.com"), new Person("Odinson", "Thor", "thor.odinson@asgard.com"), new Person("Stark","Tony", "tony.stark@stark.com")); final List<String> emailAddressList = mapper() .fromIterable() .toArrayList() .map(personList, person -> person.getEmail()); System.out.println("emailAddressList: " + emailAddressList); // Or even simpler with method reference final Set<String> emailAddressSet = mapper() .fromIterable() .toHashSet() .map(personList, Person::getEmail); System.out.println("emailAddressSet: " + emailAddressSet);
Web Method
Proprietary (at least for now)
Site:
Web-Method is a library to reveal the methods in the server-side application to the client-side application. It can work with Spring MVC.
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.lckymn.kevin.web.webmethod.annotation.ExposedWebMethod; @Controller @RequestMapping("/product") public class SomeController { @ExposedWebMethod(name = "product.listByCategory", permission = "MEMBER") @RequestMapping(method = { RequestMethod.POST }, value = "/list-by-category") public ModelAndView getProductList(@RequestParam Long categoryId) { // ... } // ... } @Controller @RequestMapping("/admin/product") public class AnotherController { @ExposedWebMethod(name = "admin.addProduct", permission = "ADMIN") @RequestMapping(method = { RequestMethod.POST }, value = "/add.json") public ModelAndView addProduct(@RequestParam Product product) { // ... } // ... }It uses other libraries of mine which are KommonLee and JSON Statham.
// register the controllers. AvailableWebMethodFinder availableWebMethodFinder = SpringWebMethodFinderBuilder .builder(jsonStatham, new ParamTypeFromClassDeciderForSpring(), new AsmMethodAndConstructorAnalyser()) .addAvailableMethods(SomeController.class) .addAvailableMethods(AnotherController.class) .build();
// when finding all the available methods for the users with certain roles. String result = availableWebMethodFinder.findWebMethodsJsonFor("MEMBER", "ADMIN");Result:
{ "product.listByCategory": { "uri":"/product/list-by-category", "params": { "categoryId":"int" } }, "admin.addProduct": { "uri":"/admin/product/add.json", "params": { "product":"JSON" } }, //... }
Trac Issues to GitLab
Trac is a good open souce issue tracking system, but when it comes to git management, Trac is rather inconvenient to use. It lacks Git supporting features. GitLab is an open source Git management application with GitHub-like look and feel as well as features and functions similar to GitHub
Trac Issues to GitLab is a small program that can help those who want to migrate from Trac to GitLab. So it can export the issue tickets from Trac then import these to GitLab.
More explanation will be added...
Example Applications
Demo: Email Address Extractor (Scala, Play Framework, CoffeeScript, etc.)
Demo: QR Code Generator (Scala, Play Framework, CoffeeScript, etc.)
More will be added.
Maven Plugins
<repositories> <repository> <id>kevin-public-snapshots</id> <name>Kevin's Public Snapshots</name> <url>http://nexus.kevinlee.io/content/repositories/kevin-public-snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>kevin-public-releases</id> <name>Kevin's Public Releases</name> <url>http://nexus.kevinlee.io/content/repositories/kevin-public-releases</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
<build> <plugins> <plugin> <groupId>org.elixirian.maven</groupId> <artifactId>buildnumber-maven-plugin</artifactId> <version>0.0.16-SNAPSHOT</version> <executions> <execution> <phase>prepare-package</phase> <goals> <goal>for-deploy</goal> </goals> </execution> </executions> <configuration> <versionInfoFile>${project.build.outputDirectory}/myapp.properties</versionInfoFile> <versionKey>myapp.version</versionKey> <buildNumberSourceFile>/path/to/versionfile.version</buildNumberSourceFile> <outputDirectory>${project.build.outputDirectory}</outputDirectory> <outputBuildNumberFileName>outputBuildNumber.ini</outputBuildNumberFileName> <parentsMustContainAnyOf> <param>My App - Build and Deployment</param> <param>My App RC - Build and Deployment</param> </parentsMustContainAnyOf> </configuration> </plugin> </plugins> </build>
Site: Maven CoffeeScript Native Compiler (Coming soon)
Site: Maven LESS Native Compiler (Coming soon)
Company: Elixirian
iSAM
Site:
Company: Elixirian Pty Ltd
iSAM (international Student Agency Manager) is an international student agency management system. The development process and technologies are similar to mQlicker's. I work with a front-end JavaScript programmer, and for this application, we are developing new APIs for the front-end and back-end which is to fetch and update many elements simultaneously to improve performance. This also reduces the amount of time spent on both the front-end and back-end development as it provides one unified way to communicate. For this project, I also implemented file system level transaction through AOP.
alkuhmee
Proprietary
Site:
Company: Elixirian Pty Ltd
Alkuhmee is a unified web API project in which I'm currently actively involved. This API is being designed to process many requests from the client-side simultaneously within only one actual request.
Project Goals
- Process many requests at one request.
- Fetch most up to date data along with processing the requests.
- Unified way to do CRUD.
UTS
TeCTra (Team Contribution Tracking)
More about TeCTra: Australian Government - Office for Learning and Teaching: http://www.olt.gov.au/resource-supporting-student-peer-assessment-and-review-large-groupwork-projects-uts-2009
I developed Team Contribution Tracking System called TeCTra for more than two years when I was a university student. It is a Java web application with Ajax techniques. Since this system was put into production in August 2007 after the first phase of the development, the UTS students and teachers have been using it to aid in peer assessment in group work. In the project, I have developed the server-side Java web application with Multi-Tier Architecture, MVC, OO design and well-known design patterns. As well as designing the server-side programmes, I programmed the entire server-side applications containing hundreds of Java class files and dozens of XML schema files. There was another programmer working on the front-end application development and we worked closely and effectively so that the project could successfully finish with a nicely working application.
When I started developing TeCTra, I was a third year university student at UTS. While I was doing this project. I came up with the idea of better and easier way to use JDBC, explained on my blog, yet didn't implement it (implementation example code is available) because Stefan told me that the Spring already had it when I was talking about the rough idea of mine with him. So instead of implementing my idea at that time, I studied the Spring framework and, after TeCTra was officially released, I migrated my code to the code using the Spring. This took me just one week to migrate. Any companies interested in migration from the legacy system to the new one with Spring framework and need a consultant, please contact me at