Skip to end of metadata
Go to start of metadata

The discussion about this started on mailing list. Below you can see this thread as a starting point of an open discussion.

 

Mike Wannamaker:

If I want to use Castor to write out objects to XML and I have getters for all attributes but I don't have setters how can I get this to work for reading it back in?

IE: The API exposes getters like String getName(); however I don't want to expose a setName(String sName); method otherwise people using the api would be able to call setName(). Is there a way to do this in Castor?

Ralf Joachim:

Hi Mike, you can tell castor to directly access the property by setting direct="true" on the field in your mapping.

You may also want to have a look at: http://castor.codehaus.org/xml-mapping.html#3.4-The-%3Cfield%3E-element

Jay Goldman:

Doesn't the use of direct="true" require the property to be public, not any better than requiring that there be a public setter. If castor would access a private property (when direct="true") or even a private setter (set-method="private_setter") then the goal of restricting updates to just castor unmarshalling could be achieved; otherwise, I haven't figured out how to get there.

I'm still using 0.9.3 - have things changed in this area?

Ralf Joachim:

You are quite right. I should have thought a bit more on my suggestion (sad)

I think we should allow to access private properties when direct="true" is set. The access to setters/getters should be still restricted to public in my opinon. Can you please search jira if there is such a issue or create a new one if not.

Werner Guttmann:

Ralf, there's actually a Jira issue, but I am not sure whether I am excited about adding this feature. The folks who designed Java must have distinguished between public and private access by thought, and I am not sure whether enabling access to something that has been designed by contract is the right way to go. I know that that feature has been added to Java, but I'd still want to respect the design of a public interface (read contract) when somebody apparently put some thoughts into this.

Just my 0.02 cents

Jay Goldman:

Werner - to try to make you more excited about the idea...I would say that a purpose of castor is to provide a mechanism for instantiating Java objects from non-Java stuff (xml, jdo). In this regard castor can be viewed as a replacement for java serialization. IMHO this gives castor license to cross the public/private 'barrier' when the user of castor has asked for this behavior (i.e., via direct="true") just as java serialization allows for the setting of private data. I would even extend it to private setters as I prefer having all access to an object go thru a setter. If the writer of the mapping has said use method SetXxx then use it. If there is no mapping file then only public methods should be used.

Moreover, it would in fact allow the user of castor to create objects with the proper public/private contracts which is currently impossible to do since to use castor you have to make all your setters (and/or members) public which defeats the whole notion of public/private.

Ralf Joachim:

In addition to Jay's arguments EJB 3.0 does not define restrictions for access to properties but access to getters/setters is restricted to public or protected methods.I'd view marshalling/unmarshalling or persistence as an internal function of the class even if its implemented externaly by castor. Therefore I would allow castor to access non public properties, maybe also getters/setters, to enable users to specify design contracts for their classes as requested by Jay. By restricting access of castor to public properties/methods we prevent or users to implement such design contracts.

Werner Guttmann:
how come we always end up talking about issues like these in regular intervals ... (wink) .

Anyhow, let's take all arguments in (incl. for example that the EJB 3.0 spec is changing in this regard, which I didn't know myself), and let's try to come to a well-defined decision. Does somebody feel like opening a page on Confluence so that everbody can share his/hr thoughts ?

 

Are there any other opinions on allowing Castor to access private or protected properties or methods?

 

  • No labels

6 Comments

  1. So to begin with, I didn't have much of an opinion on this topic, but I've been speaking with other Java programmers here at work and I think I'm starting to fall to one side of the discussion.  I agree with Werner that the public/private line was created for a reason, but the Reflection API was also created for a reason.

    In my personal experience I have had to write several classes for libraries where I don't really trust the users of the libraries to know how to create a consistent instance of a given class (yes, this is an issue in itself).  To get around this, I've begun writing very carefully considered constructors and not providing very many set methods.  Unfortunately, in one project this required me to move to Spring to do my XML persistence because Castor couldn't handle the constructor arguments I had specified (and wow Spring's XML can get ugly).  But in the end I knew that if the user had an instance of one of my classes, it would be constistent and be able to do the computations it was designed to do.  This may just be one design decision on my part as there are probably better ways to do the data handling so that the set methods keep the object in a consistent state, but at the time that didn't seem efficient.

    What really pushed me to one side is the following line of thought...  An API specifies how users are supposed to interact with classes and objects.  It specifies the required pre-conditions and the resulting post-conditions for certain actions.  If someone starts using reflection to get at things not exposed in the API, the contract of the API is essentially broken.  The developer of the API can be viewed as not responsible for the behavior of the classes/objects in such a situation.  But if on the other hand the developer him/herself explains to a framework (such as Castor) how to correctly use reflection to create objects consistent with the API and then backs that up with a schema (either XML or database) they are essentially giving the framework the permission to do its job (i.e. the framework is maintianing its contract to take valid input and produce valid objects).

    And, from a slightly less objective view, it would save me a lot of time (smile).  I think this discussion is well worth having.  The main take-away I got from discussions around here is that users are one thing, frameworks and other tools are really another.  It would be wonderful if I could specify different contracts in my API for users, persistence frameworks, and whoever else might come along (starts to sound access control lists to me!), but I can't, so I think I would prefer to help the framework violate encapsulation a little bit in order to let it do its job while protecting users from themselves.

     So, as Greg said a few days ago, I guess that is my not-as-humble-as-it-should-be opinion.

     

  2. We hand-code all of our object API; we don't use generators. The primary reason we do this is to prevent situations where we're forced to create/retain/destroy/gc a set of objects which are either decorated by disposable "business API" wrappers through composition, or having to do expensive value-object maintenance.

    On a system like ours, where the category tree alone is 8k objects, the location tree another 50-75k, and other objects which can be as many as 30-40k in number (not in size), and all of which are or can be interrelated, the cost of having to manage two sets of this information and the associated GC just isn't worth it - we get best results by ensuring that the business logic is encapsulated in the public API, and that serialization is done through other means.

    Allowing this stuff to be accessed via protected or private API removes it from the public contract; that's important for us, because our public contract is the rules on which we want the business objects to be acted upon. In some cases, we've got accessors whose sole purpose is to provide the API we want serialization to use; in other cases, we'd be more than happy deleting half of our accessors.

    Bitfields are a good example; we'd never, ever, ever want anyone to use the object's bitfield data directly - but at this point, we have no choice but to make it public. The data in question is a legacy implementation, and the meaning of the bitfields changes based on what other values are set in three other columns - you wouldn't do anything like this ever again were you doing it from scratch, of course, but that's half the point: I can hide the complexity with public API; adding the accessors as public API immediately show the underlying, ugly, hideous implementation for what it is.

    The more "leg" in your legacy database, the more slutty your objects look. And ours are ripe whores.

    I beg you - let me cover the whore's legs. Enable protected methods and private field access from XML and JDO mappings. (smile)

  3. I personally am against using such a feature as I think private methods are private for a reason, however I am leaning towards the feeling that it should be up to the end user to decide if using such a feature is right for them. It would be a pretty easy change to both Castor's introspector and the mapping loaders to add this support.

    I wouldn't make it the "default" configuration, but a simple configuration option could be added to castor.properties or the mapping file to enable the access of private and protected methods. This would be in addition to configuring the JDK security manager to allow Castor access, if necessary. 

  4. Keith, if it's that easy, can you please provide a patch for review, and I'll be taking care to integrate it asap.

  5. Sure I can do this. Do you happen to recall the JIRA issue#?

  6. Not really .... ;-(. Why not simply create a new one ?