3

I've downloaded the supposedly latest JDK 1.3 compatible binary named json-lib-2.4-jdk13.jar and am getting the following error.

Exception in thread "main" java.lang.NoSuchMethodError: java.lang.ThreadLocal: method remove()V not found
    at net.sf.json.AbstractJSON.removeInstance(AbstractJSON.java:221)

I checked the JDK 1.4 API and noticed that remove method on a ThreadLocal is indeed unsupported, and only added in JDK 1.5

The offending code is:

protected static void removeInstance(Object instance)
{
  Set set = getCycleSet();
  set.remove(instance);
  if (set.size() == 0)
    cycleSet.remove();
}

Does anyone know if I've missed something obvious here, or need an additional download or something?

Brad
  • 15,186
  • 11
  • 60
  • 74
  • 1
    Java 1.3 and 1.4 are VERY old. You should consider upgrading. Yeah, it's a little bit of work now, but that's much better than encountering a major JDK bug (or OS incompatibility) later, at which point you are totally out of luck – Adam Batkin Aug 03 '11 at 15:04
  • [Set#remove(Object)](http://download.oracle.com/javase/1.3/docs/api/java/util/Set.html#remove(java.lang.Object)) – alphazero Aug 03 '11 at 15:05
  • @Adam yes of course you are right. i'm working on some legacy code and do not have the luxury of updating the jdk just now – Brad Aug 03 '11 at 15:22
  • @alphazero. Thanks for your post. My question was incorrectly saying it was remove() missing from Set when infact the problem is with ThreadLocal which CylceSet extends. I have updated my question – Brad Aug 03 '11 at 15:32
  • It's a bug in the lib. See the answer. – alphazero Aug 03 '11 at 15:48
  • A known bug: http://sourceforge.net/tracker/index.php?func=detail&aid=3171215&group_id=171425&atid=857928 – alphazero Aug 03 '11 at 15:52

2 Answers2

3

Set#remove(Object) is certainly defined in Java 1.3. The error is actually saying that ThreadLocal#remove()V does not exist. That came in 1.5. (See? No such method!)

Here is the source of the bug in json-lib 2.4 (jdk1.3)

AbstractJSON:

   /**
    * Removes a reference for cycle detection check.
    */
   protected static void removeInstance( Object instance ) {
      Set set = getCycleSet();
      set.remove( instance );
      if(set.size() == 0) {
          cycleSet.remove();   // BUG @ "line 221"
      }
   }

Since in CycleSet.java we see:

   private static class CycleSet extends ThreadLocal {
      protected Object initialValue() {
         return new SoftReference(new HashSet());
      }

      public Set getSet() {
         Set set = (Set) ((SoftReference)get()).get();
         if( set == null ) {
             set = new HashSet();
             set(new SoftReference(set));
         }
         return set;
      }
   }

But ThreadLocal (1.3) has no such method.

[edit after @AlexR answer/comment]:

Given that the lib is open source, I think this may fix it (not tested):

   private static class CycleSet extends ThreadLocal {
      protected Object initialValue() {
         return new SoftReference(new HashSet());
      }
      /** added to support JRE 1.3 */
      public void remove() {
          this.set(null);
      }
      public Set getSet() {
         Set set = (Set) ((SoftReference)get()).get();
         if( set == null ) {
             set = new HashSet();
             set(new SoftReference(set));
         }
         return set;
      }
   }
alphazero
  • 27,094
  • 3
  • 30
  • 26
  • 2
    Thanks for confirming my suspicions. The workaround is to revert to an earlier version of the json-lib, so it is something that has been introduced in version 2.4. For those that follow I got things to work with version 2.3 (json-lib-2.3-jdk13.jar) – Brad Aug 03 '11 at 16:00
  • Great catch. I think this is a BUG indeed. Since that specific version you're mentioning is specifically targeted to run on Java versions 1.3 and 1.4. – Pablo Santa Cruz Aug 11 '11 at 11:30
0

I have just examined the code of Thread and ThreadLocal. I think that if you can at least control the command line you are using to run your application you can try to create special version of Thread that is a merge of Thread from java 1.3 with Thread from java 1.5: add thread local support.

Then fix a little bit ThreadLocal itself: remove generics and AtomicInteger used once there.

Now create jar that creates these 2 classes and put them to bootstrap classpath when you are running the application.

And a lot of good luck. If you are lucky this will probably work.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • Wouldn't it be far simpler to extend CycleSet from something else? We know what they want -- thread scoped objects -- and a Map could do the job. – alphazero Aug 03 '11 at 15:56