Category Archives: Coding

These are articles within the coding category

I needed a TriFunction

Since Java 8 you can do such nice functional things, I love it. But, for some reason it has Functions and BiFunctions, but no TriFunctions! So, it was time to add the TriFunction interface. And yes, I’m very immature ūüėõ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.util.Objects;
import java.util.function.Function;
 
@FunctionalInterface
public interface TriFunction<S, U, C, K> {
 
  /**
   * Applies this function to the given arguments
   * @param s the first argument
   * @param u the second arguments
   * @param c the third argument
   * @return K
   */
   K apply(S s, U u, C c);
 
  /**
   * Returns a composed function that first applies this function to its input
   * and then applies the {@code after} function to the result.
   * 
   * If evaluation of either function throws an exception, it is relayed to
   * the caller of the composed function.
   * @param <T>
   * @param after
   * @return 
   */
   default <T> TriFunction<S, U, C, T> andThen(Function<? super K, ? extends T> after) {
       Objects.requireNonNull(after);
       return (S s, U u, C c) -> after.apply(apply(s, u, c));
   }
}

 

Now, you can build functions that take 3 arguments and do something with them to return one result, like:

1
2
3
4
5
 TriFunction<Boolean, Boolean, Boolean, Boolean> sucks = (s, u, c) 
     -> Stream.of(s, u, c)
          .allMatch(t -> Boolean.TRUE.equals(t));
 
 boolean f = sucks.apply(true, false, true); // f is false

Guess it doesn’t suck after all!

Fixing ORD fields in Oracle

If you use Hibernate and ordered list, you’re probably familiar with having to add a column to retain the order. If you don’t want nulls in your list, you sometimes need to reorder this (say, for instance, if you manually remove an item from a list via the database).

Of course, you can do an update to “set ord = ord – 1 where ord = <first gap>” and continue doing so until you have the items nicely sequenced again. But if you have Oracle*, you can use the row_number() feature

Say you have a table ‘someTable’ and you removed a few rows from the list that is grouped by a foreign key (some_fk_id) for 123456 and you want to renumber the ORD field based on the order of inserted ID’s, you can do the following:

1
2
3
4
5
MERGE INTO someTable T USING (
       SELECT id, (ROW_NUMBER() OVER (ORDER BY id ASC) - 1) rn 
       FROM someTable WHERE some_fk_id = 123456
     ) R ON (T.id = R.id) 
     WHEN MATCHED THEN UPDATE SET T.ord = R.rn;

This will then reorder the list, starting with 0 for that group. I’m pretty sure you can write your cursors to renumber entire groups of lists

* I believe other databases have this feature as well, such as Microsoft SQL Server, however, I don’t use those, so don’t blame me when it doesn’t work there ūüėČ

 

 

Doing Enums with Jackson

Recently I’ve been working on a Jersey 2 application (a JAX-RS REST) using JSON. For the JSON serialization and deserialization I’ve chosen to use the Jackson framework. One of the reasons for this is that prior we’ve been using Freemarker templates, but if you use those, you can easily create invalid JSON which will eventually screw up your clients. Using Jackson & Jersey allow me to skip the entire Object graph to template to output chain and simply use POJOs and use annotations to model the JSON request and responses.

So basically, if I have a request/response that has a “number”, I can use those annotations to expose getter and setter methods, or choose to ignore Jackson adding a default. So in the next fragment, the getter getSomeArbitraryNumber() will be written to “number”, any incoming “number” will be mapped to setSomeArbitraryNumber and when serializing, Jackson will ignore the isNumberSet() method (without the JsonIgnore() it will expose “numberSet”):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    ...
    @JsonProperty("number")
    public Long getSomeArbitraryNumber() {
        return number;
    }
 
    @JsonProperty("number")
    public Long setSomeArbitraryNumber(Long number) {
        this.number = number;
        this.numberSet = true;
    }
 
    @JsonIgnore()
    public boolean isNumberSet() {
       return numberSet;
    }
    ...

Anyway, long story short, I ran into issues with Enums, simply because, well, you can’t instantiate a new Enum. Exposing them as JSON objects wasn’t that hard, you can just add the @JsonFormat(shape=JsonFormat.Shape.OBJECT) annotation to the class and Jackson will serialize the Enum as if it was a simple POJO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package net.sirious.jackson.enum
 
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
 
@JsonFormat(shape=JsonFormat.Shape.OBJECT)
public enum MyEnumType {
 
    TYPE_ONE("one", "this is basically just type one"),
    TYPE_TWO("two", "and this is type two");
 
    private final String id;
    private final String description;
 
    private MyEnumType(final String id, final String description) {
        this.id = id;
        this.description = description;
    }
 
    @JsonProperty("id")
    public String getId() {
        return id;
    }
 
    @JsonProperty("description")
    public String getDescription() {
        return description;
    }
 
    /**
     * Gets a MyEnumType from id or <tt>null</tt> if the requested type doesn't exist.
     * @param id String
     * @return MyEnumType
     */
    public static MyEnumType fromId(final String id) {
        if (id != null) {
            for (MyEnumType type : MyEnumType.values()) {
                if (id.equalsIgnoreCase(type.id)) {
                    return type;
                }
            }
        }
        return null;
    }
 
}

So if I had a pojo with a getter like this:

1
2
3
4
5
6
7
    ...
    @JsonProperty("myenumtype")
    public MyEnumType getMyEnumType() {
        return myEnumType;
    }
 
}

then Jackson will serialize MyEnumType.TYPE_ONE as follows:

1
2
3
4
5
6
   ...
   "myenumtype": {
      "id":"one", 
      "description":"this is basically just type one"
   }
   ...

However, deserializing is an issue, as normally Jackson expects a no-arg constructor, but you can’t have that with Enums. So you need something that can do this for you, which is a JsonDeserializer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package package net.sirious.jackson.enum.deserializer;
 
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import net.sirious.jackson.enum.MyEnumType;
import java.io.IOException;
 
public class RecurrenceEndTypeDeserializer extends JsonDeserializer {
 
    @Override
    public MyEnumType deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
 
        MyEnumType type = MyEnumType.fromId(jp.getValueAsString());
        if (type != null) {
            return type;
        }
        throw new JsonMappingException("invalid value for type, must be 'one' or 'two'");
    }
 
}

Above deserializer now allows you to accept Strings, either “one” or “two” in the JSON:

1
2
3
4
5
{
   ...
   "myenumtype":"one" 
   ...
}

And then you can use this on your POJO as follows:

1
2
3
4
5
6
7
8
    ...
    @JsonProperty("myenumtype")
    @JsonDeserialize(using = MyEnumTypeDeserializer.class)
    public void setMyEnumType(MyEnumType value) {
        this.myEnumType = value;
    }
 
}

And that’s it! Jackson will automatically get the String “one”, use the deserializer to get a MyEnumType and then pass that on your POJO. You can use this method to customize any serialization/deserialization with Jackson.

Writing your own maven plugin

As some of you may know, I’m currently working on the WCMS project at the Australian Broadcasting Corporation. This is a large, multi-year project to replace the old web content management system with a brand new (Java) CoreMedia system which will allow the ABC to grow it’s online presence even further.

As with most java based systems, we use maven to support building the project. And we use many of the plugins that are out there to do specific tasks, for instance the maven-config-processor-plugin to create the various configurations for each of the target platforms, but also the maven-shade-plugin to change some .class files in specific jars.

One of these days I needed a plugin which was able to combine a few javascript files into one big one. So I googled for a few minutes to see if there was any plugin that could do this trick. Sadly enough, I was out of luck. Every promising link resulted in using the maven-ant-plugin and writing an ant task. I’m not a fan of escaping maven and falling back on ant, so I decided to look into writing my own plugin, I mean, how hard could joining files be?

To create a maven plugin, you will need the maven-plugin-api, which you configure in the dependencies part of the pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.sirious.maven.examples.filejoiner</groupId>
  <artifactId>maven-filejoiner-plugin</artifactId>
  <packaging>maven-plugin</packaging>
  <version>1.0</version>
  <name>maven-filejoiner-plugin</name>
  <url>http://sirious.net</url>
 
  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>2.0</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
       <artifactId>maven-plugin-plugin</artifactId>
       <version>2.3</version>
       <configuration>
         <goalPrefix>filejoiner</goalPrefix>
       </configuration>
     </plugin>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <version>2.3.1</version>
         <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Note that instead of packaging this as a jar, it’s packaged as a maven-plugin. Also, because we’ll be using annotations in the actual java source, we’ll set the source and target to use java 5.

Next, we’ll have to write some code that actually knows how to join an array of Files to another File. Thankfully, the AbstractMojo already has a everything on board to create a plugin. Just create a class that extends the AbstractMojo and implement the execute() method. Note that the class is annotated in the javadoc using the @goal and @phase annotations. These define the goal (in this case, it will be filejoiner:join) and the phase for the plugin (I chose prepare-package as I needed to join the files only when we’re constructing the final jar)

As we’re joining a list of files to a single file, we need a targetFile and an array of sourceFiles. We mark these in the javadoc as @parameter and make sure they are required by marking them @required. When using our plugin in another maven project, it will now know the names of the parameters as well as inform you that you’ve forgotten to provide them. The rest of the source is pretty¬†straight forwarded, we open a file for writing/appending and we’ll read the array of source files and append them to the target file, we throw in some getters and setters and we’re done. I could have made the encoding configurable too, but I didn’t because I always use UTF-8 and I strongly think everybody should ūüėČ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package net.sirious.maven.examples.filejoiner;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import java.io.*;
import java.util.List;
import java.util.Scanner;
/**
 * @author Taco Kemna
 *
 * @goal join
 * @phase prepare-package
 */
public class FileJoinerMojo extends AbstractMojo {
  private static final String DELIMITER = System.getProperty("line.separator");
  private static final String CHARSET = "UTF-8";
 /**
  * Location of the target file
  * @parameter
  *    property="targetFile"
  *    alias="targetFile"
  *
  * @required
  */
  private File targetFile;
 /**
  * source files
  * @parameter
  *    property="sourceFiles"
  *    alias="sourceFiles"
  *
  * @required
  */
  private File[] sourceFiles;
  public void execute() throws MojoExecutionException {
    File target = targetFile;
    StringBuilder output = new StringBuilder();
    if (target.exists()) {
      output.append(readFile(target));
      getLog().info("loaded targetFile " + target.getAbsolutePath());
    } else {
      // make sure the folder we'll be writing to exists...
      if (!target.getParentFile().exists()) {
        boolean created = target.getParentFile().mkdirs();
        if (created) {
          getLog().info("created new folders " + target.getParentFile().getAbsolutePath());
        } else {
          getLog().error("unable to create target folders, exitting.");
          return;
        }
      }
    }
    // append all the sourcefiles
    for (File source : sourceFiles) {
      if (source.exists()) {
        getLog().info("appending source " + source.getAbsolutePath());
        output.append("\n").append(readFile(source));
      } else {
        getLog().error("file did not exist: " + source.getAbsolutePath());
      }
    }
    // and write the output
    write(target, output);
  }
 /**
  * Writes the String to a file
  * @param target File target file to write to
  * @param output StringBuilder containing the data to be written
  */
  private void write(File target, StringBuilder output) {
    // write the entire buffer
    Writer out = null;
    try {
      out = new OutputStreamWriter(new FileOutputStream(target), CHARSET);
      out.write(output.toString());
      out.close();
    } catch (UnsupportedEncodingException e) {
      getLog().error("unsupported encoding: " + CHARSET, e);
    } catch (FileNotFoundException e) {
      getLog().error("file not found: " + targetFile, e);
    } catch (IOException e) {
      getLog().error("i/o exception", e);
    }
  }
 /**
  * Reads a file into a String
  * @param file File
  * @return String
  */
  private String readFile(File file) {
    StringBuilder sb = new StringBuilder();
    Scanner scanner = null;
    try {
      scanner = new Scanner(file, CHARSET);
      scanner.useDelimiter(DELIMITER);
    } catch (FileNotFoundException e) {
      getLog().error("file not found while trying to read file " + file.getAbsolutePath(), e);
      return "";
    }
    while (scanner.hasNextLine()) {
      sb.append(scanner.nextLine()).append(DELIMITER);
    }
    scanner.close();
    return sb.toString();
  }
 /**
  * @return File[]
  */
  public File[] getSourceFiles() {
    return sourceFiles;
  }
 /**
  * @param sourceFiles File[] to set.
  */
  public void setSourceFiles(File[] sourceFiles) {
    this.sourceFiles = sourceFiles;
  }
 /**
  * @return File
  */
  public File getTargetFile() {
    return targetFile;
  }
 /**
  * @param targetFile File to set.
  */
  public void setTargetFile(File targetFile) {
    this.targetFile = targetFile;
  }
}

And that is all that there is to it. How maven knows to use this class? No magic there, just because you annotated it with @goal, it will be picked up by maven. So you can put multiple goals in one plugin, nicely¬†separated¬†into different classes. Of course, to deploy this plugin to your repository, you will need to add a ‘distributionManagement’ section to your pom.xml, but if you just have a local repository, running ‘mvn install’ will do.

Now, to use our plugin in another project, we’ll need to configure it as a plugin. We already decided that the execution phase for this plugin was to be ‘prepare-package’, so, we configure the ‘join’ task during that phase and we configure some sourceFiles and a targetFile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<plugin>
  <groupId>net.sirious.maven.examples.filejoiner</groupId>
  <artifactId>maven-filejoiner-plugin</artifactId>
  <version>1.0</version>
  <executions>
    <execution>
      <phase>prepare-package</phase>
      <goals>
        <goal>join</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <targetFile>${basedir}/target/combined.txt</targetFile>
    <sourceFiles>
      <sourceFile>${basedir}/src/main/resources/1.txt</sourceFile>
      <sourceFile>${basedir}/src/main/resources/2.txt</sourceFile>
    </sourceFiles>
  </configuration>
</plugin>

So, now, whenever we run the ‘prepare-package’ or during any later phase, our plugin will take 1.txt and 2.txt and append them to a new or existing combined.txt. Easy does it. I’m pretty sure that writing the plugin, distributing and configuring it in our project actually took less time than this blog post ūüôā

More reading: