Java Migration Tips

This page is a stub. For now, here's a quote from a message by Troy Howard from the mailing list detailing some of the issues. This quote is unedited from the original:
  • Note: Can someone please clean this up and formalize it into a document? Thanks, Troy


In Java, the default scoping is "package-private" which equates to .NET's "internal". A typical java class might look like the following:

public class Foo
   int bar;

public class Foo
     public int bar { get; set; }

In this case it would be necessary to expose bar via get/set properties. This is because another class, within the Lucene
package, could have read/write access to that member (and there are instances in the code where this is taken advantage of).

However if that class was listed as:

public class Foo
   final int bar;

public class Foo
    public int bar { get; }

You should only expose a get, as the final keyword is equivalent of
"readonly" in C# for that usage.

Nested Classes

Part of the conversion from java to .Net is flattening nested classes, and make all classes public, non sealed, and with an empty constructor

Sample Java Nested Classes:

public class Foo
   public static class Bar
       // ...

You may thing "oh, the nested class Bar is static, I don't need to make an interface for that". Unfortunately the static keyword, in this
context in Java, doesn't mean what you might think it does. I simply means the nested class should be exposed outside of the containing
class. It's not static in the sense that "it's a singleton, you can't instantiate an instance of it" like it would in C#.

There's a lot of scoping rules in Java that are different from .NET scoping rules and keywords are reused with very different meanings in
different contexts. For example, "final" when used in a class declaration means "sealed" but on a field in a class, means "readonly".

Some other issues are Java Attributes, anonymous types and what .NET
BCL classes to use for what Java BCL classes..

Some quick notes on that: <-> System.IO.TextReader .... BUT! .Net's TextReader
doesn't support Reset(), which is used in Java Lucene. We'll need to
make our own types.

java.lang.Number <-> System.ValueType *this is imperfect... but works
"} <-> System.Runtime.Serialization.ISerializable
*this only really maps to writeObject(..) from Java class. for readObject support, that must be an implementation detail where a specific constructor is on any serializable class.

From DIGY in the mailing list:

When “System.Runtime.Serialization.ISerializable” is used private fields are not serialized. They sould be handled via “GetRealObject” and a special constructor which can be a tedious code.(Lucene needs that private fields)
On the other hand, using “[Serializable]” attribute allows serialization of private fields.
IMO, “System.Runtime.Serialization.ISerializable” should be avoided unless very necessary and “System.Runtime.Serialization.IObjectReference” should be used when a control is needed during serialization(like “intern”ing strings).


Back to stuff from Troy's post:

java.util.Collection<T> <-> System.Collections.Generic.IList<T>
java.util.Vector<T> <-> System.Collections.Generic.IList<T>
java.util.Map<K, V> <-> System.Collections.Generic.IDictionary<TKey, TValue>

java.lang.Cloneable <-> System.ICloneable<T>
  • Deep copy or Shallow Copy? Who knows?
Brad Abrams (coauthor of Framework API Design Guidelines) discusses
this issue in a blog post here:

and basically says don't use this.. but it's all over Java Lucene.

java.lang.Comparable <-> System.IComparable<T>
java.util.Comparator<T> <-> System.IComparer<T>

If there is a method GetXXX which takes no parameters, make it a
property with a getter only. If there is a method with exactly the
same name but it's SetXXX and takes a parameter that is the same type
as returned by the GetXX (and there is no return type of the Set
method)... add a setter to the property. However, if there's a SetXXX
method that takes some other type, include the SetXXX method in the

If there is a method that takes no parameters and returns a value,
probably it should be converted to a property get even if the method
name doesn't start with "Get"... There are of course exceptions to
this.. Like .. boolean next() .. Shouldn't be a property. It probably
means the type is a enumerator and so, in the interface, we should
implement IEnumerator<T>, which has bool MoveNext() .. It also has: T
Current { get; } , which would replace whatever method on the Java
enumerator held the current value... However that might be more than
one value that is current.

In that case you should make a new type for that enumeration...


public class Foo
   // returns the current Bar
   public Bar getBar()
       // ...

   // returns the current Baz
   public Baz getBaz()
       // ...

   // moves the enumeration forward or returns false
   public boolean next()
       // ...

public class Foo : IEnumerator<BarBaz>

public class BarBaz
   public Bar { get; }
   public Baz { get; }

So... it can be a bit tricky to map things correctly and won't be exactly 1:1.

Other Conversion Odds and Ends

Also be aware of naming conventions, avoid abbreviations in favor of full words:
  • NumDocs -> DocumentCount
  • Freq -> Frequency
  • etc.
Use int/string/object instead of Int32/String/Object.

XML Comments

Useful Search-Replace tips for automatic transformation javadoc into xmldoc


search: \@param:b{[a-z]*}:b*{.*}$
replace: <param name=\"\1\">\2</param>
turns @param parser Computes integer for string values.
<param name="parser">Computes integer for string values.</param>


search: \@return{.*}$
replace: <returns>\1</returns>
@returns Blah blah
<returns>Blah Blah</returns>


search: \{\@link{.*}\}{.*}$ or \{\@link{.*}\}
replace: <see cref=\"\1\"/>\2
{@link org.apache.lucene.util.FieldCacheSanityChecker}.
<see cref=" org.apache.lucene.util.FieldCacheSanityChecker"/>.

Useful Links

Last edited Nov 20, 2010 at 9:34 PM by geobmx540, version 14


No comments yet.