The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

How do I solve this in Java?

I know how I would do this in C++ but am struggling in Java.

I have a class, C, which shares amongst its instances a static map of "things" (Ts). When all Cs are no longer needed (and this is the problem) I'd like to get rid of the map or at least the Ts inside it because they should not be valid for processing of further data although they should still be valid for other operatoins on the same data (if you see what I mean). How on Earth am I supposed to do this?

The background is that the framework I am using creates instances of C as it needs them based on its' processing of data it is passed, the C instances do part of the processing. The instances of T are common to the processing of that specific data, but should not be valid after that (in fact it would be disastrous if they were).

Friday, February 15, 2008
 
 
You can use a static WeakReference to point to your map of Ts, and an attribute that points to the map for your C objects.

In the constructor, you check if the WeakReference is null. If it is, instantiate a new map, then point from the newly created object and the WeakReference to it. If it isn't null, you just update your object's attribute.

After your C objects are destroyed, the map is garbage-collected and the cycle restarts. You may have to force a garbage collection after you're finished to make sure the map is collected.
rubinelli
Friday, February 15, 2008
 
 
Dan Fleet Send private email
Friday, February 15, 2008
 
 
Your problem doesn't seem clear.

//Contains things:
Map<Thing>things=new HashMap();

Thing thing;

//Processing a thing
process(thing);

//Removing a thing when it is no longer needed:
things.remove(thing);

???
my name is here Send private email
Friday, February 15, 2008
 
 
my name is here - sorry, maybe code helps:

class C {
  static Map m = new HashMap();
  ...
}

SomeFrameworkClass {

  public void foo(Object data) {
    // may create several instances of C, hence static Map in C
  }
}

  SomeFrameworkClass instance = new SomeFrameworkClass();
  instance.foo(a);
  ...
  // oh sh1t, now processing of b will use a's "things"!
  instance.foo(b);

Sunday, February 17, 2008
 
 
a)  You're trying to make static do something it isn't supposed to do.  If it isn't going to be shared among all instances of the class, it *should not be static*.  Give each C a reference to a container of T, which can certainly be held in common with multiple other instances, rather than a static reference to a container of T.

b)  When your all of your C pass out of scope, the container of T will be garbage collected away.  If you want to accelerate this process slightly, empty the collection(s) of T.

c)  I sort of shudder at giving this suggestion because I fear it is going to cause cargo-cult coding, but if you had a Factory of C, you might be able to implement this properly without requiring the code duplication that is likely encouraging you to implement this the wrong way currently.
Patrick McKenzie (Bingo Card Creator) Send private email
Sunday, February 17, 2008
 
 
If you need it to be static for some reason (and I don't think there is one) you can do this:

static Map<SomeFrameworkClass, Map<C, Object>> m = new HashMap();

...with each SomeFrameworkClass associating itself with a map. Obviously, this is a runtime duplication of making them member variables.
my name is here Send private email
Sunday, February 17, 2008
 
 
> Give each C a reference to a container of T,

I can't, because they're created by the framework. Client code doesn't "see" any instances of C in order to pass them the reference, except the first one it creates (I tried to simplify the example hence it not being shown).

> static Map<SomeFrameworkClass, Map<C, Object>> m ...

Java 1.4 :-(

Monday, February 18, 2008
 
 
Throw away the framework.It's more hassle than it's worth.
rubinelli
Monday, February 18, 2008
 
 
How would you solve the problem in C++?

I'm a little confused over exactly what parts of which classes you have access to.

How about a static Count int? Increment the count variable upon instantation. Decrement it upon cleanup. If the count is zero after decrementing, nuke the map.

Your biggest problem is that since you can't explicitly destroy the object, you have to have a "dispose" method that you can call at some point. Otherwise, it might not get Garbage Collected in time, before a new instance is created.

If your framework prevents you from creating a dispose method, I don't think your problem can be solved in Java.
Rohan
Monday, February 18, 2008
 
 
Actually, after thinking about it a bit more, is this an accurate description of your problem:

You have some C1s, which are associated with map T1.
You have some other C2s, which are associated with map T2.

Can you work a level higher?  Create a class P which contains a collection of Cs and one T. Have the Cs connect to the parent P, and access the correct T through the parent. Then when you are done with T, destroy P.  That way, you prevent Cs with interacting with Ts in a different P.

I'm not sure what your framework will allow you to do, though.
Rohan
Monday, February 18, 2008
 
 
> How would you solve the problem in C++?

Actually having gone through the thought processes when writing this, I'm not sure I could!

Tuesday, February 19, 2008
 
 
Is this like you have a set of "Cars" that are operated on by a set of "Robots" that are part of an "AssemblyLine" ?

Each individual robot does something distinct to the set of cars, and the robots are told to start by the assembly line.  When done you need to swap in another set of cars?  Each startup of the line may have a different set of robots depending on configuration.


It sounds like your framework is mucked up.

Can't you just pass the set of "T" (as per your original comment) to the outer method of your framework, and it in turns sets the static map on "C", and does the processing?

e.g.
Map myTMap = new HashMap();
// put some Ts into myTMap
instance.foo(a, myTMap)

How much control over the framework do you have?
Dan Fleet Send private email
Tuesday, February 19, 2008
 
 
As others have said, it's obvious that Class C is misdesigned. It is a global variable, but it is used as if it was a parameter passed to process().

It seems like your descriptions are a bit contraditory. In the beginning you make it sound like all Cs operate together on the Ts, but your sample code suggests that the Ts are actually both restricted to use by one particular instance of C in one call of process().

You need to clarify to yourself what you are actually trying to accomplish. Is the assembly line metaphor accurate or is it something different?
Dotimus Send private email
Wednesday, February 20, 2008
 
 
"It is a global variable, but it is used"
Should read:
It contains a global variable which is used
Dotimus Send private email
Wednesday, February 20, 2008
 
 
> How much control over the framework do you have?

http://www.castor.org/  So not a lot at all, really.

I wanted to avoid implementation specifics as much as I could, but...

It is related to Java->XML marshalling. Basically I need to generate specifically named elements to send to external systems and can't introduce something like xslt (don't even go there!) to do so after the event, so am using a custom implementation of XMLNaming which generates (i.e. looks up the alias) when called by the framework. The items in my map are the alias mappings from Java classes to XML. That's not a problem.

The problem is the aliases have to be shared between all calls for a specific "document type", but the names to be used may be (are) different for other "document types" (possibly even for the same classes to be marshalled...). So, if client code tries to have Castor marshal two types of document in sequence all hell could break loose if the client code doesn't do the right thing (even leaving aside any threading issues that might occur).

Maybe the client code can work around this, but I don't like leaving that kind of hole open for the unwary to fall into later on (you know, if I get hit by the project manager's proverbial bus), I'd prefer to wrap this kind of peculiarity with code that DTRT.
Don Quixote :-(
Thursday, February 21, 2008
 
 
>>The items in my map are the alias mappings from Java classes to XML. That's not a problem.<<

Unless I misunderstood you, that IS the problem. This map should not be global. I'm still not sure who wrote Class C. If you can change it then do! It seems like the mapping should be document-type specific. So why not make map like this:

Map<DocumentType, Map<String, String>> theDocumentTypeSpecificElementNameMapping;
Dotimus Send private email
Friday, February 22, 2008
 
 
> It seems like the mapping should be document-type specific

I agree with you. That's exactly what I want. The problem is that the instances of C are created by the framework, not client code. Each is involved in processing a part of the document. So there are a number of Cs for each document, but no way (that I can see) to tie document x's Cs together and keep them separate from document z's (the constructors have to follow the pattern expected by the framework, and there's no way for calling some intialization code from outside). I was wondering if I could use an instance initializer for the map which somehow can work out which document it should be related to and get the related aliases somehow based on that, but how I'm supposed to do that I don't know (although I do have an idea, and really don't want to go there).

> Map<DocumentType, Map<Str...

As I said before, we use 1.4. Generics were introduced in 1.5.

Friday, February 22, 2008
 
 
As I said before, we use 1.4. Generics were introduced in 1.5.

This doesn't matter. You just have to hard cast in 1.4. Generics are only syntactic sugar.
Shirly
Friday, February 22, 2008
 
 
Can you not expose your own API to the client such that the client has no idea what's going on with the framework? This way they call some method on a library you ship, and your implementation does whatever magic is necessary to ensure the wrong map isn't set in the framework.
Dan Fleet Send private email
Friday, February 22, 2008
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz