When Strings Are Not Immutable In Java

Give this code shot and see what happens:


public class MutableStrings {
    private static void toUpperCase(String str) {
        try {
            Field f = String.class.getDeclaredField("value");
            f.setAccessible(true);
            f.set(str, str.toUpperCase().toCharArray());
        } catch ( Exception e ) {
            // yes, I'm eating an exception! (cuz the above turns out to be a *horrible* idea, so why not compound it with another bad practice?)
        }
    }

    public static void main(String... args) {
        final String greeting = "Howdy";
        toUpperCase(greeting);
        System.out.println(greeting);
        System.out.println("Howdy");
    }
}

You should get the very unexpected output of:


HOWDY
HOWDY

What just happened??


So, I was having fun the other day with reflection in one of the Java classes I teach at Neumont University. Based on some cool stuff I learned when I got GSSP certified two years ago, I proposed that strings could possibly be mutable if Java was run without the security manager, making setAccessible(true) available. Sounds like it's worth a try:






public final class MutableStrings {
    public static void toUpperCase(String str) {
        try {
            Field f = String.class.getDeclaredField("value");
            f.setAccessible(true);
            f.set(str, str.toUpperCase().toCharArray());
        } catch ( Exception e ) {
            // yes, I'm eating an exception! (cuz the above turns out to be a *horrible* idea, so why not compound it with another bad practice?)
        }
    }
}

With this handy method, I can now pretend that strings are, indeed mutable.

Instead of


public final class Mainer {
    @Test
    public void testStringToUpperCase() {
        String greeting = "Hello";
        greeting = greeting.toUpperCase();
        Assert.assertEquals("HELLO", greeting);
    }
}


Now, I can do


    @Test
    public void testStringToUpperCase() {
        String greeting = "Hello";
        MutableStrings.toUpperCase(greeting); // notice the lack of assignment on the left
        Assert.assertEquals("HELLO", greeting);
    }
}

But, WAIT, there's more!


Because Java uses a String pool, two separate references set to identical string literals can point to the same reference, e.g.


    @Test
    public void testStringPoolEquals() {
        String greeting = "Hello";
        String salutation = "Hello";
        Assert.assertTrue(greeting == salutation);
    }
}

Because greeting and salutation point to the same reference in memory, if I change the value property in String reflectively, I get the following behavior:


    @Test
    public void testStringToUpperCaseStringPoolCorruption() {
        String greeting = "Hello";
        MutableStrings.toUpperCase(greeting);
        String salutation = "Hello";
        Assert.assertEquals("HELLO", greeting); // okay, makes sense
        Assert.assertEquals("HELLO", salutation); // wait... WHAT??
    }

Woah, what just happened?? Why did salutation get changed as well? Well, now we've come full circle: Strings are pooled in memory in Java. When I do "String variableName = string-literal;", it will search the string pool for that string and fashion a reference pointer to that object in memory instead of creating a new one. When we edit the internal value directly, everyone that points to that same object will get the modified value instead.

Less effective...


Obviously, this is a terrible idea. :) Imagine the chaos of something like string comparison failing because someone reflectively changed the underlying char[] array of a string-pooled public static final variable. It also seems like it could be exploited somehow, tricking an application into rendering malicious information to an end user, like in the case where a hacker gets arbitrary code to run on the server.

Still, it's fun to amaze your friends!

1 comments:

"Have You Done Your 20 Minutes of Reading...er...Coding today?"

When I first became a parent, I was filled with the excitement of being able to teach my kid everything that I knew. I'd teach him how to be creative, responsible, curious, empathetic (at least as far as I understood them), but I'd also teach him fun things like the first 314 digits of pi, juggling, basketball, and coding.

Yes, coding. As a software engineer, I never worked a day in my life. I *love* to code. It's fun. I'd do it even if I weren't paid to do it. And actually, now that I'm a teacher full-time, I can make good on that claim. Although the majority of my day is now spent teaching, I still squeeze in time to code, and it is largely for the fun of it.

To my coding friends: Do you remember the thrill that came from the first time you got your computer to do something you programmed it to do, even if it was simple? I personally remember getting my first Pascal book in high school, and I literally could not put it down. One particular memory I still have from my 14-year-old self is sitting in the back seat in the McDonald's drive thru, nose stuck in my Pascal book while my sisters talked about Jonathan Taylor Thomas or some such*.

I wanted my kid to have the same thrilling experience, the same overwhelming passion. I wanted to see the deep focus come over them that comes over me when I have a terribly abstract and difficult problem to reason around and the subsequent exultation when they finally see the light at the end of the tunnel and realize that they did it.**

For me, teaching my kids coding was always a want. I heard about Scratch, and I downloaded it. I learned about Greenfoot and downloaded it. I tried them both on my kids with a mild amount of success. I spent an afternoon with my 8 and 10 year old boys and built an animation where three stick people would run up a ladder, slide down a slide, and fly into the wall, including sound effects that would only attract 8 and 10 year old boys. Another afternoon, we built an LDS missionary app where the missionary had to walk around and visit all the houses before the "bees" caught him. On another day, we built a simple frogger game. Another, we built a "Family Home Evening Spinner". We had fun.

Now, though, I believe I'm transitioning. "I want" is slowly turning into "I should" or "they need".

Reading Coding is Fundamental


I think about coding like I think about reading and writing. Research, studies, and our own intuitions seem to confirm that reading aloud to our children every day enstills within them a skill that will assist them in solving big problems, getting a larger world view, and generally being productive in society. Clearly, not being able to read and write is an enormous disadvantage in this day and age.

In parts of the world where literacy is low, those who are literate are invaluable to their community, often serving in positions of leadership and working at the forefront of the community's biggest problems.

Sound like what coders are doing today? One need only look as far as heavily code-literate institutions like Google to see some of the impressive problems that are now being solved today that were once considered intractable or at least only part of the distant horizon.

As Gabe Newell from Valve put it: "The programmers of tomorrow are the wizards of the future. You're going to look like you have magic powers compared to everybody else."

I'll take that a step further, though. I don't only want my kids to have those "magic powers" in order to make big, positive differences in the world. They are going to need them.

Douglas Rushkoff explained that "When we acquired language, we didn't just learn how to listen, but also how to speak. When we acquired text, we didn't learn just how to read, but how to write. Now that we have computers, we are learning to use them but not how to *program* them."

Largely, the world seems satisfied to allow themselves to become increasingly dependent on "geeks" for increasingly fundamental aspects of their day to day lives. Many not only consider the inner workings of computers and the Internet "unknowable" but even "worthless to know".

However, I believe that such an imbalance between the knows and the know-nots, while convenient in the short term, will put those who don't know how to code at as much of a debilitating disadvantage in the future as not knowing how to read does today. Those who could write centuries ago formed the world in the image they saw as multitudes of non-readers consumed their perception of reality, often independent of its accuracy or precision.

For me, teaching my kids coding was always a want. Now, though, "I want" is turning into "I should" or "they need".

Our children are the consumers of the digital revolution that many of them cannot currently participate it at a production level. Their perceptions even now are being molded by the coders behind Facebook, Google, Instagram, and Twitter. If our youth do not know how to code themselves, they are destined to be relegated to the class of citizens who consume points of view formulated not necessarily by those who are right but by those who are simply more skilled at the lingua franca.

As Patrick Byrne from Overstock once quipped: "Mark Twain once said don't pick a fight with someone who buys ink by the barrel. I say never pick a fight with someone who buys bandwidth by the gigabyte." Kids needed to learn to write. Kids now need to learn to code, too, if they are going to have a say in the makeup of our future world.

"Have Your Done Your 20 Minutes of Coding Today?"


For some of my kids, they love reading so much that they don't need to be reminded. One of my kids reads at the dinner table, in closets, and with a flashlight late into the night. Another reads because it is on her "job chart" and she wants to put down the check mark. A couple of them need to be reminded over and over again if I want to have any kind of output from them.

Regardless, they all know that Mom and Dad expect them to read 20 minutes a day. We read them bedtime stories, we read the Bible and Book of Mormon every night together as a family. They know that Mom and Dad love to read and like to carve out time for our own personal reading during our day.

Kids need daily time coding as well, and it needs to be on the job chart. Or, if that seems too daunting, families can try the rule that we enforce in our house:
When on the computer, be a producer, not a consumer.
My kids are allowed to build stuff in Minecraft, draw pictures in paint, make sound effects and animations in Scratch, learn something new by researching online or anything that basically is not straight up media consumption. We have "Cummings Cash", and I tie that Cummings Cash to certain bounties that are related to them building, creating, and making stuff on or off the computer.

It's time for the Cummings's to level up, though. With our oldest two children (8 and 10), I want them to get familiar with coding more than just as a pastime. So, for one week, I decided to try something new.

The regimen was simple: Work on codeacademy, a codemonkey level, or something coding-related for 20 minutes a day together for one week. I considered the pairing up part to be super-important as my older son is more responsible, but my younger son has more of the "knack". Hopefully together they'd stay on task.

In addition, it's also been on my mind to see whether or not a non-coder parent can help a non-coder kid become more familiar with coding. I imagine that mother or father 300 years ago who had never learned how to write, but now perceived the need for her children to learn to write. What would she do in such a situation to help her children make progress?

So, while not the greatest comparision, I decided that as an additional experiment, I'd ask my wife--a non-coder--to sit in with the boys for those 20 minutes a day. She would follow along with the exercises and help the boys out if they got stuck. We called it the "Code With Your Child" initiative.

To my delight, my wife accepted the challenge! This week, she is working through the exercises with the boys; sometimes she sits and watches, but mostly the boys work on the tasks independently and she verifies after they are done. It's going well! My boys are learning coding from a non-coder! I will post a detailed update when our experiment finishes next week.


In the mean time...


Why don't you give it a shot yourself? IMHO, everyone should know at least a little bit about coding. And maybe pull your kid in with you while you do it.

*Actually, I'm sure my sisters were more sophisticated than that. Kimmie would accept nothing less then Jason Priestly or that one guy from New Kids On The Block.

**My wife tells me that she knows it was a really hard problem when I yell out a "Whoop!" when it finally works.

0 comments:

On Code as the Resume: Two Creative Code-Resumes That Helped Me Get Hired

11:53 AM 0 Comments

Read about five others after you are done here!
A traditional resume is a PDF or doc file with sections like Objective, Work History, and Education neatly organized into columns and sometimes squeezed onto a single sheet of paper for rapid perusal of keywords.

It's important to stand out, though, and as long as you are standing out, why not have a little bit of fun with it?

The two stories that follow are two times where I wrote code as my resume. This isn't a portfolio nor an assigned coding assignment from the interviewer. The code is a resume and the resume is written in code. Hopefully, they will give you some ideas on being creative with the job application process.

XKCD: Meta-Analysis

DNA

About 6 years ago, I was applying for an internal position at my company. The team developed tools and libraries for the rest of the 20-30 development teams in the organization which meant that its standards for acceptance were pretty high.

When I became familiar with some of the folks interviewing, I got a little nervous. One definitely had more experience than I.

So, I determined to create a resume that would demonstrate my coding skills in addition to acting as a traditional resume.

Welcome Adam.java. When run in the following manner:


java Adam

It will print out the resume to the console as you might expect.

This is already a little bit nerdy, but not nearly enough to draw their attention. It's probably just enough trouble to annoy the interviewer instead of bump me up the charts.

Welcome Eve.java. Now, run the application in the following manner:


java Adam Eve

And the two will randomly splice a new resume together, creating a new Java file: Adam_Eve.java. It will have taken some of the attributes from the Adam resume and some of the attributes of the Eve resume to make a new, randomly mutated resume that has some of the attributes of each of its precessors.

Now, Adam_Eve can be run:


java Adam_Eve

to see the new resume, OR


java Adam_Eve Eve

to generate a new mutated resume.

I sent the above instructions in my job application as well as the Java files Adam.java, Eve.java, Seth.java, and Carol.java. I stated that they should feel free to splice resumes with each other until they obtain a resume that they like.

The words from one of the devs made my day: "That was the coolest resume we have ever received." Happily, I got the job. :)

I have this code hanging around somewhere, but I made what I thought was a better one later on that was a Mission Statement Generator. You can read about it in the README at its github link: https://github.com/jzheaux/mission-statement-generator. It wouldn't be too difficult to alter mission-statement-generator's code to generate a resume, if you wanted to try it out!

MaSH

I had a client once who stated that he needed Maven, Spring, Hibernate, Amazon EC2, and JAX-RS experience. He also wanted to see a portfolio. The portfolio was moderately problematic: I don't really have one since nearly all my work over the last 15 years has been backend.

So I decided that there was no time like the present. I turned on my stopwatch and started to build a resume out of Maven, Spring, Hibernate, Amazon EC2, and JAX-RS. Three hours later, I had something simple but that clearly demonstrated that I could build a multi-module project using Spring and Hibernate, deploy it to Amazon EC2, and use CXF (a JAX-RS provider) to create a client and ReSTful server.

You can see the code here:  http://github.com/jzheaux/resume

You can see the resume here: http://resume.joshuacummings.com/resume/100

And you can query the ReSTful API here: http://resume.joshuacummings.com/resume-ws/resume/100

For example:

curl -H  "Accept: application/vnd.joshcummings.com-v1+json" http://resume.joshuacummings.com/resume-ws/resume/100

As you can see, the app doesn't do much other than demonstrate each technologies' "happy path". However, I liked that it was "meta" and, in the end, they hired me so maybe it was worth it.

Should you do this?

In each case above, the situation was somewhat specialized. In the first, it was an internal position, so I knew a couple of the devs that would be looking, and I knew that they were total geeks and would love seeing a resume like that. Also being internal, the volume of resumes was low so I knew they would likely take a minute to actually follow my instructions to run the program.

In the second, I again knew that the application volume was low; further, they had asked for a portfolio, so really I was combining their two requests into one by sending them a product that shared the relevant resume info, demonstrated in the context of a portfolio.

On the other hand, there are several stories of people doing various stunts that both demonstrate their ability to do the job and get them noticed at high profile companies like Google.  Then there are application tactics that are simply memorable, but don't really manifest the applicants abilities.

So, maybe there is some benefit other than the personal satisfaction of "going meta".

What's Next

While more boring, the second one I think is better because it is easy to inspect everything; some non-engineer doesn't need to fiddle with java command-line to see the resume. It also retains the potential for video, audio, and other application-oriented stuff to actually make it a more delightful experience.

Maybe if I ever apply for an Android position, I'll create a resume app with a Mutate button on it. Doesn't that sound like fun?

0 comments:

Neumont Coding Contest 2015 - Qualifying Round Solution

4:06 PM , 0 Comments

Courtesy University of Buffalo


Beware! Solutions follow! First, read the Betsy Ross problem and see if you can come up with your own solution.



Here is one of the submitted solutions to the Betsy Ross problem posted in the previous blog post:


public class BetsyRoss {
 
 public static void main(String[] args) {
  Scanner input = new Scanner(System.in);
  
  String line = input.nextLine();
  Integer starCount = Integer.parseInt(line);
  
  double bestColumnCount = starCount;
  double bestRatio = starCount;
  for ( int n = starCount - 1; n >= 1; n-- ) {
   int remainder = starCount % ( n + ( n - 1 ) );
   if ( remainder == 0 || remainder == n ) {
    double rowCount = starCount / ( n + ( n - 1 ) ) * 2 + (remainder == 0 ? 0 : 1);
    double ratio = Math.max(n, rowCount) / Math.min(n, rowCount);
    if ( ratio < bestRatio ) {
     bestColumnCount = n;
     bestRatio = ratio;
    }
   }
  }
 
  System.out.println((int)bestColumnCount);
 }
}

Math


Amongst the fastest-submitted solutions, the most important realization for students was that the odd/even complexity could be reduced by envisioning the rows in odd-even pairs. Either a flag would be comprised of all odd-even pairs (or even-odd pairs) or there would be one odd (or even) row left over.

This means that if one is testing with seven starts on the top row, the flag can be thought of in 13-star groups (7 + 6) with a possible 7 left over. This means that if the total number is evenly divisible by 13 or if it has a remainder of 7 (meaning one additional odd row), then we have a match.

Note that the same principle works if the first row has an even number of stars on the top row. In the case of 8 stars on top, the flag can be though of in 15-star groups (8 + 7) with a possible 8 left over. This means that if the total number is evenly divisible by 15 or if it has a remainder of 8 (meaning one additional row), then we have a match.

Reducing this step of the problem to mere mathematics saves us inner loops that might need to discover the fact empirically, making the solution faster and writable in fewer lines of code.

Max


Another simple construct in problems like this is a max counter. The problem set stated that the number of rows and columns needed to be as close to identical as possible. When looping through experiments, one can keep track of the current best, updating it only when a better one comes along.

Improvements?


Please post below your improvements! The above code runs in under 5 seconds on nine-digit numbers on my machine.

0 comments:

Neumont Coding Contest 2015

10:00 AM , 0 Comments

This year, we decided to hold a coding contest at Neumont University. We did a single-elimination, head-to-head competition roughly similar to the Top Coder Single Round Matches, just with two people in a room instead of 20. We started with 50 entrants, whittled it down to 32, and then, five rounds later, we had our winner!

Because I was in charge of coming up with the problems, I thought I'd post what they were for each round, what some good (and bad?) solutions were, and anything else that comes to mind.

I'll also possibly post a bit on the coding contest server that I built using Spring 4 to teach myself a bit about Java Config.

Qualifying Round

First, the rules: Students could use any IDE and could submit solutions in C# or Java. No Internet, but they could bring in pencil and paper. For the qualifying round, students were given the entire day to solve one problem. Students were be ranked in the order they submitted a correct solution up to 32 submissions.

So, at 10am on February 17th, students were presented with the following problem:

Betsy is interested in flags whose stars are formatted rectangularly where every odd row is the same length and every even row is one star less than the odd rows.

Furthermore, call the width of this flag the number of stars in its first row and the height the number of rows. Betsy prefers the dimensions to be the closest to a square as possible. In the case of a tie, Betsy prefers flags with more columns than rows.

For example, in the case of a 50-star flag,

Betsy likes a flag whose odd rows have 6 stars and whose even rows have 5 stars (resulting in a flag with 9 rows of stars, 6, 5, 6, 5, 6, 5, 6, 5, 6) as opposed to a flag whose odd rows have 5 stars and whose even rows have 4 stars (resulting in a flag with 10 rows of stars). A 6 x 9 flag is closer to a square than a 5 x 10 flag.

For example, in the case of a 46-star flag

Betsy likes a flag whose odd rows have 7 stars and whose even rows have 6 stars (resulting in a flag with 7 rows of stars, 7, 6, 7, 6, 7, 6, 7)
as opposed to a flag whose odd rows have 12 stars and whose even rows have 11 stars (resulting in a flag with 4 rows of stars). A 7 x 7 flag is closer to a square than a 12 x 4 flag.

Create a Solution that reads in the number of total stars from standard in and prints out the number of stars in the first row of Betsy's preferred flag.

Here are some sample inputs and outputs:

50 -> 6
46 -> 7
115 -> 12
112 -> 4
3 -> 2
459384753 -> 28603

The first correct submission was submitted within 40 minutes of the announced problem, and by the end of the day, 29 students were in. How fast can you complete it? I'll post a couple of solutions and my analysis next time.

0 comments:

Three Simple Steps to Convert from EJB 3 to Spring 4

1:46 PM , , 2 Comments

While the merits of doing so are debatable, a client of mine wanted to covert his EJB application into a Maven, Spring, Hibernate application.

His application was small--about 75 classes. The only significant aspects of EJB that he was using was dependency injection and RMI. He did not up to that point have a need for persistence, so there were no existing ties to JPA. He was; however, tied to Jersey 1.x and currently needed a dependency from Netbeans in order to build the product (weird?).

Some of the above may sound similar to your situation. What I'll describe below is how we

1. Migrated the product from Ant to Maven, turning it into a multi-module project.
2. Migrated from EJB to Spring
3. Upgraded from Jersey 1.x to 2.x

Maven


As the product stood, it would build an .ear file that exposed a remote interface over RMI and a .jar file that invoked this remote interface. Insofar as we were abandoning EJB for Spring, it would suffice to create a jar file on both sides.

These had a common dependency, which was the shared interface, so I recommended that we create a multi-module maven project which would allow the client and server to both be dependent on an api project. Also, they could all be built with a single command and be automatically related to each other in modern IDEs.

The new project structure

The file structure will change a bit; here is what it will look like in the end:


/product-name
  -- pom.xml
  -- /api
  ---- pom.xml
  ---- /src
  -- /client
  ---- pom.xml
  ---- /src
  -- /server
  ---- pom.xml
  ---- /src

The master pom

The master pom ties everything together, specifying which and in what order modules should be built:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://maven.apache.org/POM/4.0.0"
 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>com.company</groupid>
 <artifactid>product-parent</artifactid>
 <packaging>pom</packaging>
 <version>0.0.1-SNAPSHOT</version>
 <name>Product Parent Pom</name>

 <modules>
  <module>api</module>
  <module>server</module>
  <module>client</module>
 </modules>

 <properties>
  <spring.version>4.1.4.RELEASE</spring.version>
 </properties>

 <build>
  <plugins>
   <plugin>
    <groupid>org.apache.maven.plugins</groupid>
    <artifactid>maven-compiler-plugin</artifactid>
    <configuration>
     <source>1.8</source>
     <target>1.8</target>
    </configuration>
   </plugin>
  </plugins>
 </build>

 <dependencies>
  <dependency>
   <groupid>junit</groupid>
   <artifactid>junit</artifactid>
   <version>4.12</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
</project>

The API Project

Then, the API project. For now, this will only contain a single file that needs to be shared between the client and server. In all likelihood, RMI will be abandoned in favor of JAX-RS or Spring MVC down the road, but right now we are changing as little code as humanly possible.


<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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>com.companylt;/groupId>
  <artifactId>product-parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
 </parent>

 <artifactId>api</artifactId>

 <name>SDA Api</name>
</project>

The API has just one interface and it not annotated with any EJB or Spring annotations; those are placed on the implementations. Because of this, notice that this api has no dependencies, which can come in handy later on if the client wants to use different libraries from the server.

Client and Server

The client and server have several dependencies; I'll try and highlight the important ones:


<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>
 <parent>
  <groupId>com.company</groupId>
  <artifactId>product-parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
 </parent>

 <artifactId>client</artifactId>
 <packaging>jar</packaging>

 <name>Product Client</name>

 <dependencies>
  <!-- API Dependency -->
  <dependency>
   <groupId>biz.keyinsights.sda</groupId>
   <artifactId>api</artifactId>
   <version>${project.version}</version>
  </dependency>

  <!-- Spring Dependencies -->
  <dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-expression</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <!-- A particularly important dependency -->
  <dependency>
   <groupId>org.springframework.integration</groupId>
   <artifactId>spring-integration-rmi</artifactId>
   <version>4.1.2.RELEASE</version>
  </dependency>

  <!-- Other dependencies not listed -->
 </dependencies>
 <build>
  <finalName>product-client</finalName>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.1.1</version>
    <executions>
     <execution>
      <phase>package</phase>
      <goals>
       <goal>java</goal>
      </goals>
      <configuration>
       <mainClass>userInterface.ClientUserInterface</mainClass>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</project>

Finally, the Server's pom, which I won't post because it is largely the same as the client pom.

The last thing I needed/wanted to do was rearrange the project structure so that it matched Maven's default. This means putting all the source code into src/main/java, all the resources into src/main/resources, and all the JUnit tests into src/test/resources. Pretty simple.

Now, a simple "mvn clean install" from the parent will do all the work!

Spring



RMI

When in EJB, the interface was exposed via the @Remote EJB annotation. Spring has a nice RMI library, so it was a simple matter of removing the EJB anntotations and providing the correct Spring wiring:

Client-side

@Configuration
@ComponentScan("userInterface")
public class AppConfig {
 @Bean(name = "userInterface")
 public RmiProxyFactoryBean remote() {
  RmiProxyFactoryBean b = new RmiProxyFactoryBean();
  b.setServiceUrl("rmi://localhost:1199/RegressionService");
  b.setServiceInterface(UserInterfaceRemote.class);
  return b;
 }
}

Server-side

@Configuration
@ComponentScan({"session.client"})
public class AppConfig {
 @Inject UserInterfaceRemote service;
 
 @Bean
 public RmiServiceExporter rmiServiceExporter() {
  RmiServiceExporter exporter = new RmiServiceExporter();
  exporter.setServiceName("RegressionService");
  exporter.setService(service);
  exporter.setServiceInterface(UserInterfaceRemote.class);
  exporter.setRegistryPort(1199);
  return exporter;
 }
}

So far, no business logic or design changes; just wiring.

Dependency Injection


In EJB, beans can be made eligible for dependency injection via the @Stateless annotation, which was the case here. I replaced these with the appropriate Spring stereotype, e.g. @Service, @Component, etc.

There were a couple of @Stateful annotations (ew) which I could have replaced with the @Scope annotation in Spring. Fortunately, however, the "statefulness" of those beans turned out to be an artifact from a discarded approach, so I replaced those with @Service as well.

On the auto-wiring end, I replaced @EJB with @Inject

And finally, I added the Java Config on both the client and the server to bootstrap Spring:

Server-side


public class MyWebApplicationInitializer implements WebApplicationInitializer {

 public void onStartup(ServletContext servletContext)
   throws ServletException {
  servletContext.addListener(new ContextLoaderListener(createWebAppContext()));    
 }

    private WebApplicationContext createWebAppContext() {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(AppConfig.class);
        return appContext;
    }
}

Client-side


public static void main(String[] args) {
     AnnotationConfigApplicationContext context =
             new AnnotationConfigApplicationContext(AppConfig.class);
        ClientUserInterface ui = context.getBean(ClientUserInterface.class);
        ui.go();
}

Excellent, no code changes! To the existing code, we only modified annotations. We added wiring code and maven configurations.

Jersey


No project goes perfectly, though, and my excitement was tempered by discovering that Jersey's support for Spring 3+ was added in Jersey 2.x. Grrr. Upon attempting to upgrade, by changing the version in the maven pom, there were several places in the code where compilation failed.

The Jersey Migration Guide to the rescue! Especially section 27.16.2, which covered how to change client request from 1.x style to the 2.x style and 27.16.3 where JSON support is explained.

Updating Jersey Client API

I found the Jersey 2.x Client API to be a little confusing when it came to setting headers. Somehow this:

Response response = target.request("text/plain").get();

is setting the Accept header for the request to be "text/plain", which is a change from using the accept() method to set the Accept header.

And how to set the content type for the request? There doesn't appear to be a contentType() method or something similar; it appears to be retreived from the entity sent in the post method:


Response response = target.request("text/plain").post(Entity.entity(payload, "application/xml"));

The typical Jersey Client request appears to be a three-line cocktail of obtaining a Client, deriving a WebTarget via the Client, and then invoking the target to get a Response. In the code I was upgrading, there were several repeated sections of these three lines of code. Grrr! However, at the time I just needed to be surgical about it and not do a bunch of refactoring, so I left the copy-pasta for another day.

JSON Support

Replacing JSON support was super easy: It was simply adding the appropriate jackson-jaxrs-json-provider dependency to maven.

HACK: Ghost applicationContext.xml

There was only one really cheesy thing that I didn't find a good way around. After upgrading to Jersey and following the docs to get Spring and Jersey to play nicely (at least as I understood it to that point), I would always get an exception that said that Spring could not instantiate multiple ContextLoaders. This was really frustrating as I knew that I already had one in my Java config (see above).

By doing some debugging into Jersey, I found this in Jersey's SpringWebApplicationInitializer:


@Override
    public void onStartup(ServletContext sc) throws ServletException {
        if (sc.getInitParameter(PAR_NAME_CTX_CONFIG_LOCATION) == null) {
            LOGGER.config(LocalizationMessages.REGISTERING_CTX_LOADER_LISTENER());
            sc.setInitParameter(PAR_NAME_CTX_CONFIG_LOCATION, "classpath:applicationContext.xml");
            sc.addListener("org.springframework.web.context.ContextLoaderListener");
            sc.addListener("org.springframework.web.context.request.RequestContextListener");
        } else {
            LOGGER.config(LocalizationMessages.SKIPPING_CTX_LODAER_LISTENER_REGISTRATION());
        }
    }

In short, this is looking to see if there is an applicationContext.xml referenced in the ServletContext already; if not, then create one and add a ContextLoaderListener to the servlet context as well.

The fact is that since I'm using Java config, I don't have an applicationContext.xml! So the first half of the if statement was always running. To get around it, I added a ghost reference to the web.xml file to an empty applicationContext.xml file and it worked like a charm!

Conclusion


Other than one particular library incompatibility, migrating to Maven, Spring 4, Hibernate, and Jersey 2.x was pretty straightforward. Enjoy!





2 comments: