views:

202

answers:

5

I have the following code:

Map<String, ObjectType> objectMap = new HashMap<String, ObjectType>();
for (ObjectType obj : objects) {
    obj.setSomeProperty("property value");
    objectMap.put(obj.getADiffProperty(), obj);
}

It seems like during loop iteration some of the obj property changes for different keys than the one currently being set. Is there a problem with the above code? Somehow the reference to obj is being recycled by the for loop?

Also this loop is in an outer loop as well.

Update:
I am providing the full method below. The actual place where I am observing the behavior described above is in the outer map defined as Map<String, Map<String, GlossaryTerm>> loadedTerms = new HashMap<String, Map<String, GlossaryTerm>>(); defined in a Singleton class.

List<Audience> audiences = ContentAccess.getAudienceList();

List<GlossaryTerm> glossaryTerms = ContentAccess.getAllReplacementCIs();                            

for (Audience audience : audiences) {                   
    Map<String, GlossaryTerm> termMap = new HashMap<String, GlossaryTerm>();
    for (GlossaryTerm term : glossaryTerms) {
       String definition = term.getProductGlossary().get(audience.getName());
       if (definition != null)
           term.setDefinition(definition);
       termMap.put(term.getPhrase(), term);
   }                        
   loadedTerms.put(audience.getChannelId(), termMap);
}
A: 

This might be just a typo error. There is no object declared in your snippet, but your put call uses object.getADiffProperty() rather than obj.getADiffProperty(). Is that intentional?

Lord Torgamus
Yes that was a typo, corrected it. Thanks for pointing it out.
Eqbal
And here I thought I solved your problem. I'll take another look.
Lord Torgamus
+2  A: 

It seems like during loop iteration some of the obj property changes for different keys than the one currently being set. Is there a problem with the above code? Somehow the reference to obj is being recycled by the for loop?

The obj variable will be set to the "next" element of the iterator for objects each time around the loop. If you see the same reference value in obj more than once it can only be because:

  • the reference value genuinely appears more than once in collection, array or whatever given by objects, or

  • something in setSomeProperty or getADiffProperty or something else you are doing in the loop is updating objects as a side-effect, or

  • the objects object has a buggy iterator implementation.

Another possibility is that what you are seeing is different objects with the same adiff values.

To say anything more, I'd need to see more source-code than the simplified snippet you have provided.

EDIT - the extra code you provided has not revealed the problem. (I think we can dismiss any theories involving updating the lists while they are being iterated, or strange side-effects from the setters.)

My suspicion is that one of those lists that the singleton is providing contains duplicates or something else unexpected. It could be that is what is causing your problem.

Do what @Carl suggests and use traceprints and/or a debugger to figure out what is in the Collection singleton and what your code is actually doing.

EDIT 2 - The fact that the collection thingy is a singleton class is probably irrelevant. And the contents of a HashMap DO NOT change randomly or spontaneously. (And there are no little green demons in your code that conspire to make it fail. Trust me on this!)

You seem to have the mindsight of guessing what the problem is and making changes based on those guesses in the hope that they will fix the problem. STOP GUESSING! That is the wrong approach, and will probably only make things worse. What you need to do is debug the code carefully and methodically, gathering hard evidence of what your program is actually doing, and interpreting that evidence carefully ... without resorting to crazy notions that something is changing things randomly.

EDIT 3 - If I was in your situation, I would ask another experienced Java programmer in the team to sit down with me and help me debug the code. I still occasionally need to do this myself, and I've had 10 years+ Java experience and 30+ years programming experience. Sometimes you get a mental block on a problem, and a fresh mind / fresh approach is the answer.

It is not a shameful thing to admit to your team / boss that you are out of your depth and need help.

Stephen C
I updated my complete method above. Maybe its the Singleton causing the issue, although in my tests I am running one thread and Singleton is implemented as a statically instantiated variable like `private static SingletonClass instance = new SingletonClass();`
Eqbal
As to your suspicion I moved the list from Singleton to local. Even tried getting rid of Singleton. No difference. Maps seem to change randomly!
Eqbal
As to guessing, see my comment to Carl about how I worked around the issue and of course I have people screaming at me to deliver the fix NOW!!! I suspect a bug in the Java runtime. I am going to try another JDK.
Eqbal
@Eqbal - a bug in the Java runtime is *highly* unlikely. This is "little green devils infest my code" thinking.
Stephen C
Thanks for the advice. I am trying. Although the fact that I have a work around means I may have to move on! I don't want to leave this though without figuring out whats happening here.
Eqbal
+1 for the advice of getting someone else to go through it with you in the debugger. It's not necessarily even a matter of "depth", it's a matter of the limits of human perception and the value of getting a second opinion.
Joe Carnahan
+2  A: 

I don't think what you think is happening, is happening. The object reference is what it's supposed to be, for each iteration. I think something else must be happening - that the properties are changing elsewhere, or don't have the values you think they have initially. Put in some printlns to track down what's really going on. The code you've shown can't be changing the wrong properties.

Carl Manaster
I am running a debug and observing the `HashMap` (the outermost one) and an entry I am specifically looking for gets put in correctly and during the progression of the loop it changes on me! Very odd!
Eqbal
Can you put a watchpoint on the field that changes, then see when it changes? Or: could you be overwriting the entry - do multiple terms have the same phrase? Or phrases with the same hashcode?
Carl Manaster
The keys are Strings. Can two Strings have same hashcode? That maybe the problem. I am debugging and will let you know. These strings are all 40 char length GUIDs basically.
Eqbal
It might help if you provide the code for Audience, GlossaryTerms, and ContentAccess
portoalet
So, I modified the code in the following way: instead of `termMap.put(term.getPhrase(), term);` I instantiated a new `GlossaryTerm` object and copied over the values from `term` and then put this new instance into `termMap`. Now its working correctly. It seems like using the variable from the `for each` loop isn't safe in a Map. Why???
Eqbal
That just can't be right. I don't mean to question what you are seeing - I believe you - but it should be 100% safe to use the foreach variable. Something else is going on here, and it would be good to track it down and understand it, because you don't want to learn falsehoods about the language that lead you into paranoid coding. If you want to put all the code up somewhere, I'd be happy to look at it.
Carl Manaster
I am not sure if putting my code up will help as the two method calls to ContentAccess go over to get content from a remote server (act as weblogic client). Maybe we can try reproducing this by hardcoding the response we get from ContentAccess.
Eqbal
@Eqbal - I agree with @Carl Manaster. There is something else going on here. As I said on my answers, I suspect that the collections themselves are broken. (Maybe your code really is multi-threaded and you don't realise it. Maybe the `equals` and `hashcode` methods are inconsistent for some class. Maybe you are mutating key objects in hash tables. Maybe something else.)
Stephen C
@Stephen It beats me! Maybe weblogic remote call is making my call multi-threaded? Maybe its serializing my objects and then not deserializing right? As to `equals` and `hashCode` I am using `String` as my key so that should be okay!
Eqbal
@Eqbal - what about the keys in Maps and Sets in your collection code?
Stephen C
Every key in each and every `Map` is a `String` object. Not using any `Set`. Using `ArrayList` . What do you mean by keys in Sets? Does the fact that instantiating a new object and copying over the contents from the iterator object fixes the results give you any hint as to what could be happening? FYI, ran with another JDK (JRockit) and same behavior. So most likely not a bug in Java runtime.
Eqbal
A: 

From where the code is called? May be there are concurrent issues? Are there other threads (is it a webapp?) accessing ContentAccess? And I hope GlossaryTerm is a simple Dto, right?

Arne Burmeister
Well, I am testing from a single thread in my eclipse. Eventually it is/will be called from inside a webapp/servlet. Yes, GlossaryTerm is a simple DTO.
Eqbal
+1  A: 

I'm starting a new answer because - well, it's a new thought here, and the discussion thread was getting rather long.

You haven't (I think) said when the changes happen. But you are (potentially) putting the same term into multiple maps, for different audiences. Nothing to do with the loop variable - just that you are repeatedly using the same list of terms, for each audience. But when you put the term into a map, you also change its definition. But the definition is (potentially) different for each audience. So, concrete example:

Term A has the definition of "x" for audience X, and "y" for audience Y. You have both audiences. Initially, we encounter audience X, so A gets definition "x". A gets added to the map for this audience. Now we iterate to the next audience, and change the definition for A to "y". This changes A everywhere you have a reference to it - including in the map for audience X. This would explain why making a copy eliminates the problem. Is this what you are experiencing?

Carl Manaster
You have hit the nail on its head here! That is exactly what I am seeing!!! Thank you very much!
Eqbal