• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Jeanne Boyarsky
  • Ron McLeod
Sheriffs:
  • Paul Clapham
  • Liutauras Vilda
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

A setter that can only be called by framework

 
Ranch Hand
Posts: 782
Python Chrome Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

FooDTO is a Data Transfer Object. I also have a Foo class which is a domain object which is managed by some ORM framework. I have another class, DTOconverter which will convert between Foo and FooDTO instance. Currently Foo & FooDTO are in different package. And DTOConverter is in a util package.

Is there any way to enforce the condition that the setter setId can only be called by class DTOconverter and never by any client who does this:


Thanks
 
Ranch Hand
Posts: 208
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Pho Tek:
Is there any way to enforce the condition that the setter setId can only be called by class DTOconverter



The following might work:



but it is rather, shall we say, "hairy".

Instead, I recommend exploring the possibilities of your framework, which might have some other way of doing this - intercepting calls to the setter, and do the check in a seperate class completely. Because what I suggested above is not exactly loose coupling, and thus to be avoided if possible.

What framework are you using?
[ November 03, 2006: Message edited by: �dne Brunborg ]
 
Pho Tek
Ranch Hand
Posts: 782
Python Chrome Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am using BEA KODO (for the persistence framework). Thanks for the solution.
 
Ådne Brunborg
Ranch Hand
Posts: 208
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Of course, this solution is intended to be called with "this" (i.e. the calling object) as the first parameter. There is nothing to stop callers from using "new DTOconverter" instead and thus fool the check.

I don't know BEA tools, but I strongly recommend you try to find some BEA way of doing this. Maybe this page can help?
[ November 03, 2006: Message edited by: �dne Brunborg ]
 
Ranch Hand
Posts: 547
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Another one for the "hairy" section :-)
Use a Thread local to store a "magic key". In the converter set the magic key to the Thread local. In the setId() method get the magic key, compare it using DTOConverter.isValidMagicKey(key).

As said: hairy :-)

You could examin the caller stack but this is also hairy, probably slow and might be dependant on JVM.

Or you could just trust the programmers ?

pascal
 
Ranch Hand
Posts: 55
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now you want something hairy...

You could put the "setId" method private.
An then call this method by reflection from
your DTO converter.
An exemple : Reflection/Private
 
Ådne Brunborg
Ranch Hand
Posts: 208
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There is also the simple solution of making the setters protected and put them in the same package as the converter, but that is rather old-fashioned and a little boring.
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You could eliminate the setters on the DTO and make DTOConverter pass all values to a constructor. If there are too many fields for that, you could make a MutableDTO parameter to the ImmutableDTO constructor. That's starting to seem like a lot of effort to prevent ... exactly what bad thing from happening?
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It sounds like probably the goal is to have the DTO to be immutable after the initial building phase. It's not at all uncommon for DTOs to have too many fields for it to be practical to initialize everything in the constructor. And for my taste, I think anything more than two or three fields is too many - I dislike seeing constructors with long lists of arguments whose significance can be determined only by their order.

So, I like Stan's suggestion of having a MutableDTO and ImmutableDTO - though I'm not sure I understand the "make a MutableDTO parameter to the ImmutableDTO constructor" comment. I like the idea of having the two classes related much like StringBuilder and String. You have a mutable class that you can do whatever you want with, and then when the data is set the way you want, you convert to the immutable version with a toString() method - or toImmutableDTO() method, as the case may be. You can probably find a better name. I like the idea that a FooDTO should have a mutable FooDTOBuilder, or perhaps a nested class FooDTO.Builder. Unfortunately, it's a bit tedious to write a mutable builder class for every DTO, unless you're using code generation of some sort.

An alternative that may be a bit simpler to code is to create a freeze() method which, once you call it once, it becomes impossible to make any further changes to the object. I shamelessly stole this idea from Ruby and played around with it a bit, but haven't applied it on a real project. Here's what I came up with:

This makes it fairly easy to write classes like Foo. The immutability is enforced at runtime rather than compile time, which is a bit unfortunate, but it should work. Something to consider, anyway.
[ November 03, 2006: Message edited by: Jim Yingst ]
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To answer the original question as it was asked (assuming you don't like the other suggestions better): I think you could probably do this using a SecurityManager (for enforcement at runtime), or using AspectJ (enforcing at compile time or runtime, depending how you set it up). Either approach would require some extra effort learning the details of how these technologies work, if not already familiar. Personally, I'd pursue the ideas about making the DTOs immutable, before trying either of these approaches.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

though I'm not sure I understand the "make a MutableDTO parameter to the ImmutableDTO constructor" comment.


Ah, my notion was something like:

Immutable could use gets() on mutable and assign its own variables directly with no setters at all.

I like your notion that the mutable object is a factory or somehow renders itself as the immutable one. Makes the immutable one have no dependence on the mutable one. Would the mutable one use a bunch of protected or package scope setters to load the immutable?

There's nothing to prevent anyone from using the mutable one. Maybe it has no public getters which would make it useless outside the package?

Good puzzle anyhow!
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Stan - thanks for the clarification. The ImmutableDTO(MutableDTO) constructor seems fairly obvious in retrospect, but somehow I was thinking you meant something else. Never mind. It's certainly one of the possible ways to go from mutable to immutable object, and not a bad one. I tend to avoid calling constructors directly in many of my classes, preferring factory methods of one sort or another. But that's a minor difference - it wouldn't be hard to replace your constructor above with ImmutableDTO.createFrom(MutableDTO) method. Either way there's another minor tedious bit I'd like to avoid, where you have to write a copy constructor or something similar, transferring all values from the MutableDTO to the ImmutableDTO.

[Stan]: I like your notion that the mutable object is a factory or somehow renders itself as the immutable one. Makes the immutable one have no dependence on the mutable one. Would the mutable one use a bunch of protected or package scope setters to load the immutable?

Well, I tend to favor making the mutable Builder a nested class inside the class it's supposed to build. That way it has direct access to the private variables of the top-level class. In reality this is implemented with package-access synthetic mutator methods. But as long as I don't have to write them or look at them, I'm happy.

[Stan]: There's nothing to prevent anyone from using the mutable one. Maybe it has no public getters which would make it useless outside the package?

Yeah, I go back and forth over which of those I prefer. Consider String vs. StringBuilder - neither is a subtype of the other. You can write a method that requires a String parameter, and you will get an immutable String, period. Whether it was originally constructed with a StringBuilder is irrelevant. Or, you can write a method which takes a CharSequence parameter, which may be a String, or StringBuilder, or something else. In general one might think it's good to write to the more general interface, but not always. Here is a recent example of how that can cause confusion. That's one of the reasons I like immutable types where possible.

Here's an idea I had for making a reasonably simple mutable Builder / immutable DTO pair:

The getters and setters are easy to auto-generate an any major IDE, but the build() method requires a bit more tedious work. Well, tedious if there are 20 or 100 rather than the mere 2 in this example. Or one can fiddle about with code generation to take care of it. But I'd prefer something that scales better as the number of fields increases, with less redundant code. We can use the Prototype pattern, implement Cloneable, and let clone() take care of all the copying:

This still seems like an annoying amount of boilerplate code for something that really should be simpler, in my opinion. But that's what I've come up with so far, in my attempts to reconcile my preference for immutable objects with my dislike of constructors with long lists of unlabeled arguments. Open to further suggestions...
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
People who have trouble moving from other styles to OO often complain that OO seems to introduce a lot of complexity to achieve simple design goals. I'm feeling that way, now, too. I kinda like where you're going, but I'd look to a code generator for builders and avert my eyes from the generated code.
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yeah, agreed. But even using code generators - what would you want them to build? Or maybe the details don't matter as much as long as you usually don't need to look inside the generated code.
 
Space seems cool in the movies, but once you get out there, it is super boring. Now for a fascinating tiny ad:
Smokeless wood heat with a rocket mass heater
https://woodheat.net
reply
    Bookmark Topic Watch Topic
  • New Topic