views:

323

answers:

17

I'm teaching an intro to programming course and we're using Java. I want to help the students learn how to translate a written class specification into a working program. I will provide the written specification. It specifies the name of the class and behavior in the form of method signatures. I want the students to translate that into a working Java class.

I could provide them an interface and have them implement the interface, but that defeats part of the purpose: to read and interpret a written functional specification document. I want them to write the class from scratch. Then I want to grade their work.

My idea for checking their work is this: compile their Java class file against my own interface. If it compiles, then at least I'll know they've followed all the method contracts and I can start testing the functionality. If it doesn't compile, I'll get an error message reporting which methods were not implemented correctly.

How can I force a Java class file to be compiled against an interface even if none was originally specified in the source code?

In other words, let's say I have the following two files:

FooInterface.java

public interface FooInterface
{
    ...
}

Foo.java

public class Foo
{
    ...
}

I want to compile Foo as if it implemented FooInterface explicitly. But I don't want to have to manually edit a bunch of source code files in order to do so. How can I do it?

Edit

To address questions about the value of using a written spec vs providing the interface, here's what a hypothetical specification document looks like:

Write a class called Foo with the following methods:

oldest : ages (int[]) -> int
Given an array of ages, return the highest one.

anyAdults : ages (int[]) -> boolean
Given an array of ages, return whether any of them are 18 or older.

IMO, this has a great educational benefit. The student has to critically evaluate whether their program obeys the spec. If I provided the interface file, they could unplug their brain and simply have the compiler tell them whether or not they were following the spec. Using the compiler as a cognitive crutch is the same technique the poorer students currently (unsuccessfully) employ to balance their braces and parentheses.

+10  A: 

You could maybe do something like:

public class Bar extends Foo implements FooInterface{}

If FooInterface is fully satisfied by Foo then Bar will not have any errors.

jonnii
The problem here will be *that defeats part of the purpose: to read and interpret a written functional specification document*
OscarRyz
@Oscar. Here OP will be providing Bar and FooInterface; Foo class written by the students doesn't know of FooInterface
notnoop
@notnoop: Yeap, now reading Murali answer that makes sense. Originally I just thought it was a simply contradiction with OP said.
OscarRyz
I kinda like this solution.
Barry Brown
+10  A: 

You could still have Foo implement FooInterface but just give your students an empty FooInterface. When you compile students' Foo use your actual FooInterface.

Murali VP
+1 definitive solution
OscarRyz
If the students haven't yet learned about interfaces they will question what an interface is. I think this is more confusing.
jonnii
Agree with you, with your solution, they won't have to know anything about FooInterface :-)
Murali VP
+2  A: 

I don't know if this is the most elegant way to do it, but your grading program could use reflection to load the student class and look for methods with a given name - if it doesn't have such a method, you can deduct whatever points you want. If the method does exist, then you can invoke it using reflection as well, passing in whatever parameters you like.

Sun has a pretty decent tutorial trail here:

http://java.sun.com/docs/books/tutorial/reflect/member/index.html

See the section on obtaining method information and invoking methods.

Marked community - others please feel free to provide corrections, etc.

weiji
A: 

I don't know if you can do this at compile time, but here's an idea. Why not check at runtime by creating a class of type Foo and checking to see if it is an instanceof FooInterface? Hope this helps. I tried to think of some sort of solution with annotations, but nothing I can come up with works at compile time.

Amir Afghani
This won't work. Unless Foo is actually declared to implement FooInterface, then `instanceof FooInterface` will always return false regardless of whether the methods match.
Phil Ross
Wasn't that part of the original constraint set out by the OP to check for correctness?
Amir Afghani
+3  A: 
OscarRyz
+1. Exactly what I meant by my comment above.
ChssPly76
Which is all extrapolated from one of many possible ways to describe a specification. See my comment above.
weiji
A: 

Best what you could to is to compare the methods using reflection or to create a proxy class as outlined here.

BalusC
+1  A: 

@weiji's reflection idea sounds really good although it might make things really complicated from your end
Maybe you could write another class which inherits from their class but additionally implements the specified interface, and is filled with dummy methods which simply call the corresponding functions in the parent class

adi92
A: 

One thing that you could do is say that you are going to test the output of their program. In order for them to have the code executed, they need to create an empty interface like IGradeable.

They can define it as they wish. When it comes time for them to hand it in, you could define your IGradeable interface like this:

public interface IGradeable extends FooInterface
{
....
}

Just a suggestion. The only other way that I can think of is to do something like create temporary java files and do a regex replace to have all files implement FooInterface.

bogertron
A: 

You could use reflection to see if the student's class implements all of the methods defined by your interface.

Steve Kuo
A: 

I agree with jonnii's answer. Student does not have to implement the Foo interface. It is the teaches that creates one class only that extends the Student's class and implements the interface.

John
+1  A: 

You cannot do what you want to do unless you process their source.

If you REALLY want to do this, then you can write a program that loads their class, and uses reflection to inspect the methods to see if their signatures conform to what you want them to be. A lot of elbow grease is needed.

Personally I would suggest that they collaborate on definitng the interface in class before the project is assigned, and then say that THAT interface must be used.

Thorbjørn Ravn Andersen
+1  A: 

It's hackish, but can't you just use a tool such as sed to insert "implements YourInterface" as appropriate?

I know this would be hard if there were a load of classes with different names, but it seems there is only one class for them to submit so it'd be ok.

If this approach is really abhorent then feel free to critique for the sake of posterity in the comments.

Tom Duckering
It's worth saying. This is your worst-case solution. Never actually hand-edit dozens of files to make the same change; what a waste of your time!
Kevin Bourrillion
It's definitely on my list of tricks.
Barry Brown
A: 

Using AOP, you can weave the students' classes and synthetically let them implement FooInterface at runtime and run your test suite against them. This can be done fairly easy and automated using custom class loaders for each student.

However, i'm unsure about how this will behave at runtime when the class does not actually implement all the methods with correct signature, e.g. if it just throws MethodNotFoundErrors

aspect MakeImplementFooAspect {
  // makes many classes implement FooInterface
  declare parents : edu.teaching.foo.* implements FooInterface;
}
mhaller
-1 overkill award!
Kevin Bourrillion
+3  A: 

In addition to providing a complete Interface when you compile your students code as Murali suggested, I suggest you also implement a unit test suite to make your grading go much more smoothly. In addition to testing that the method contracts from the written spec are all met, you could also be testing that each method works properly.

Bill the Lizard
He would be providing too much information already don't you think?
OscarRyz
No, the unit tests would be just for his own use, not to be shown to the students.
Bill the Lizard
Yeah, you *totally* have to do this. It frees you from the burden of manually evaluating all their submissions for correctness. You can focus on other things.
Kevin Bourrillion
Oh I see. And that would be coded to the "private" interface +1
OscarRyz
That's exactly what I'm going to do. The problem here is the JUnit test class won't compile if even one thing is misspelled. I'd prefer have it compile so I can test the things that were implemented correctly rather than die completely and disallow any testing at all.
Barry Brown
A: 

By the way, be sure to require each student to include his or her full name in the class name. That way you have the option of compiling all these things at the same time, so you'll really save a lot of time.

Also either require a specific package name or, simpler, no package at all.

Kevin Bourrillion
+1  A: 

Another thing you could do is have them write the interface and then the class. So you could give them the requirements, and have them write a class w/ methods that meet those requirements, as well as have them write an interface that said class implements. So you would have:

InterfaceFoo{
 ....
 }
Foo implements InterfaceFoo{
 ....
 }

Then you could just have a class w/ the methods defined, and implement InterfaceFoo, if it compiles then you know the students correctly created the correct methods and signatures, if it doesn't then the compiler will let you know what they missed.

broschb
+1  A: 

If the specification contains exact method signatures, you might as well supply the interface as the students will not really be writing the interface but copying it from the spec.

If the specification is not exact (just describing the parameters of each method) then you should probably not use an interface, because there may be many valid interpretations of the same method or parameter description (protected vs. public, different argument order, List vs. array vs. Iterable, BitSet vs. Set<Integer> etc.) You should not penalise your students just for coming up with a working solution that does not exactly match yours.

finnw