• 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
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Transfer objects

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

I'm about to submit (Bodgitt Scarper) but, upon reflection am thinking about making some changes regarding sending and receiving data between client and server. My original approach only put the information I received from a search into an object (actually an arraylist of Contractor objects). Everything else I left as individual data items - for search I only sent a String[] containing the search criteria and for booking I sent Long (the record #), String[] (the original contractor info from the JList to be used to check against any changes by other users) and String (the booking data). I'm thinking now of putting all this in transfer objects. However:

1) wrapping the String[] for search in a transfer object seems wrong (in fact someone explicitly argued so) and I tend to agree.

2) putting my booking data (long, String[] and String) into an object seems correct but overkill for such a small application.

How did other people address this question? Did people use all transfer objects or a mix?

Thanks
Dave
 
Sheriff
Posts: 11604
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Dave,

A quick and short overview of my approach:
  • I had transfer objects for all communication between client and server
  • I didn't wrap the String[] into a transfer object, but my transfer object simply had a data member for each record field (with a specific type instead of String), so I had also 2 methods to convert a String[] to transfer object (and vice versa)
  • I had a seperate transfer object used for transferring the search criteria to the server. The main benefit is obvious, so I let you think about that one yourself
  • For booking a room I used my room transfer object and the customer id as a parameter of the book-method. my transfer object contained the id (record number) of the room


  • Hope it helps!
    Kind regards,
    Roel
     
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Did you make the members in your transfer object public? Or did you provide getter\setter methods?

    I'd guess you provided getter\setter methods. Providing a getter for every member and providing a setter for every member apart from the record number? And thus you wouldn't provide a no-argument constructor - but a constructor that takes the record number as the parameter? Reason being you don't want the client to be able to modify the record number.

    You mentioned that you had a utility method to convert an String array to a Room object and vice-versa. How did you handle the fact that the arrays your Data class would be expecting would not contain the record number? When you pass a Room object into your utility method that converts it to a String array, did your utility method return an array that contained the record number or not? Same with regards the other direction, did your utility method that converts a String array to a Room object expect an array that contained the record number?

    If your utility method that converts a Room object to an array returns an array that contains the record number, then you'd need to copy the contents of this array of length N into an array of length (N -1), leaving out the record number in order to send it on to your Data class.

    I am of course assuming your Data class expected an array that did not contain the record number - which I think would be the case as you must pass the record number in as a separate argument. So adding it to the array also wouldn't be a great idea.

    The correct thing to me would seem to be that yes the arrays accepted\returned by these utility methods must contain the record number. Firstly because you should not be allowed create a Room object without a record number, and you shouldn't have a setter for the record number. So if the utility method to convert a String array to a Room expects the record number, then the other utility method should return the record number. Whilst it seems correct to me at the this level, I dislike the fact that when it comes to sending the information on to my Data class, I won't be provided with an array than I can use - as it will contain the record number.
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    1/ no getters/setters in the transfer object
    2/ String[] does not contain the record number, the record number is passed seperately
     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:1/ no getters/setters in the transfer object


    Interesting that you've no getters\setters - am I correct in thinking that means a client who receives your transfer object can modify the record number and send it back to the server? Is that not a concern?

    Where were your two methods to convert the transfer object to/from an array - were they in the transfer object class?

    Roel De Nijs wrote:2/ String[] does not contain the record number, the record number is passed seperately


    I'm not sure if you are talking about your DB API here or your conversion methods. Does that mean that:

    * Your method to convert an String[] array to a Room object has two parameters - the String[] object and an integer record number?
    * Your method to convert a Room object to a String[] did not contain the record number in the String[] ?
     
    Ranch Hand
    Posts: 170
    Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:

    Roel De Nijs wrote:1/ no getters/setters in the transfer object


    Interesting that you've no getters\setters - am I correct in thinking that means a client who receives your transfer object can modify the record number and send it back to the server? Is that not a concern?



    i think he already pointed out that the record number isn't stored in the room (and it shouldn't, the room shouldn't know
    about it's index in some database so this value has nothing to do in a Room Object/array.

    Sean Keane wrote:
    Where were your two methods to convert the transfer object to/from an array - were they in the transfer object class?

    Roel De Nijs wrote:2/ String[] does not contain the record number, the record number is passed seperately


    I'm not sure if you are talking about your DB API here or your conversion methods. Does that mean that:

    * Your method to convert an String[] array to a Room object has two parameters - the String[] object and an integer record number?
    * Your method to convert a Room object to a String[] did not contain the record number in the String[] ?



    why would you need the record number for the conversion?
    besides, methods in the DAO (such as update) get the data and the record number. doesn't that make obvious the
    fact that the record number is not included in the String[]?
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:Interesting that you've no getters\setters - am I correct in thinking that means a client who receives your transfer object can modify the record number and send it back to the server? Is that not a concern?


    Yes, you are correct! Why would that be a concern? You may expect of a developer that he knows what he's doing, so if he decides to change the record number of a room transfer object always to 1 that's his choice.

    Sean Keane wrote:Where were your two methods to convert the transfer object to/from an array - were they in the transfer object class?


    In a seperate utility class.

    Sean Keane wrote:I'm not sure if you are talking about your DB API here or your conversion methods.


    All String[] in my application are the same size (and they do not contain the record number, because there's no need to), so the assumptions you made are both correct.
     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

    Sean Keane wrote:Interesting that you've no getters\setters - am I correct in thinking that means a client who receives your transfer object can modify the record number and send it back to the server? Is that not a concern?


    Yes, you are correct! Why would that be a concern? You may expect of a developer that he knows what he's doing, so if he decides to change the record number of a room transfer object always to 1 that's his choice.



    My thinking on why you'd prevent the record number from being modified is quite simple - encapsulation. The same reason you make some methods private - because you don't want a user of your API to be allowed call them. Of course you could make the methods public and just document that they shouldn't be called. But you don't do that.

    There's no reason why user of your API who receives an object representing a record should be allowed modify the record number. By preventing a user of your API modifying the record number you are making your system safer, more robust, and the code more intuitive.

    Think of it in terms of getters\setters. If you had getters\setters on your transfer object. All members on your transfer object are visible and mutable - this is identical to saying you have getters\setters for every member on your transfer object. Having a setter for the record number implies you support this operation - so having the record number mutable and visible implies you support modifying it. But that is not your intention. You don't expect or want a user of your API to set the record number - you just hope they wouldn't be that silly and would read your documentation. So why convey in the code something you don't actually want a user of your API to do? It's misleading and leaves room for error.

    Why leave this possibility for someone being mislead, using your API not as you intended, or errors occuring when you can code against it by preventing the record number from being modified. It seems like a no-brainer.

    Roel De Nijs wrote:

    Sean Keane wrote:I'm not sure if you are talking about your DB API here or your conversion methods.


    All String[] in my application are the same size (and they do not contain the record number, because there's no need to), so the assumptions you made are both correct.



    So your method that converts an array to a Room object expects two parameters - the String[] object containing the record information and the int record number.

    See, that's what I was battling with when thinking about putting these methods on the Room object. It would seem odd to have a toArray() method that returns all the members of the class bar the record number. But the toRoom() method would expect either (a) an array containing the record number or (b) two arguments - an array and the record number.
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:The same reason you make some methods private - because you don't want a user of your API to be allowed call them.


    True, but only methods which are guaranteed never to be called are made private (e.g. reading/writing 1 record from/to database file).

    Sean Keane wrote:You don't expect or want a user of your API to set the record number


    For the record number I don't have that guarantee. In your API you'll have the possibility to give you room object a record number (because you need it yourself). And because you have that opportunity, an API-user can always change the record number (it only needs a bit more code). So why making it hard for your API-user if you can make it simple and easy.

    Sean Keane wrote:Why leave this possibility for someone being mislead, using your API not as you intended, or errors occuring when you can code against it by preventing the record number from being modified. It seems like a no-brainer.


    Then you should simply use getters/setters in your room object.
     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

    Sean Keane wrote:The same reason you make some methods private - because you don't want a user of your API to be allowed call them.


    True, but only methods which are guaranteed never to be called are made private (e.g. reading/writing 1 record from/to database file).



    Is there any good reason why you would not guarantee that a user of your API can never set the record number of a Room object?

    I could think of reasons why you would guarantee they couldn't set it (list in previous post) - but I can't think of any reasons for the contrary.

     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:Is there any good reason why you would not guarantee that a user of your API can never set the record number of a Room object?


    Like I already said: because you can set the record number (through a constructor I suppose) an API-user will also be able to change the record number (he just creates a copy of the instance with another record number).

    According to the Transfer Object design pattern using no getters/setters could be done, which results in less (and cleaner) code, but you lose encapsulation. Just another trade-off.
     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

    Sean Keane wrote:Is there any good reason why you would not guarantee that a user of your API can never set the record number of a Room object?


    Like I already said: because you can set the record number (through a constructor I suppose) an API-user will also be able to change the record number (he just creates a copy of the instance with another record number).



    Ah yes. Now I see where you are coming from. You are saying there is no point in making the setter for the record number private - because the constructor will have to take the record number as an argument to allow the Room object to be created on the server side, so there's nothing stopping the client creating a new Room object with whatever record number they like.

    So, based on this, you aren't actually gaining anything by making the members of the Room class private and using getters\setters. Agree with your reference (which I had ) that it results in cleaner code.

    Ideally what I would like is to send a Room object to the client where they can't modify the record number and can't pass back a Room object that wasn't created on the server side.
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:Ideally what I would like is to send a Room object to the client where they can't modify the record number and can't pass back a Room object that wasn't created on the server side.


    I have no idea why you would do such a thing Let's say in the next release of the application there should be a create-button which makes it possible to add new rooms to the database file, I would expect you create some kind of form with all room details which user can enter. Then a Room object is created (without primary key), all values from the form are copied into the room object and the BusinessService.createRoom method is invoked.
     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Well a simple solution would be to create the Room class in the package that contains my BusinessService. Make the no-argument constructor public, make all getter\setter methods public except for the setter for the record number which we make package protected.

    That would mean my Business class could set the record number when returning a record to the client code. But the client code would not be able to modify the record number as it lives in a different package.

    If the client code wanted to create a Room object, then they could do so as the no-argument constructor is public. They could then set all the fields using the setter methods. But the only field they couldn't set would be the record number as its setter is package protected and the Room class lives in a different package, so the client code won't have access to it.

    Problem solved
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The problem will not be solved at all. What if you want to put all your transfer objects in a seperate package? And I'm quiet sure that with using reflection I can easily invoke your protected setter (or just set the record number through the Field reference). Or I can do easily something like this (no hacking, just a bit of OO):

     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:The problem will not be solved at all. What if you want to put all your transfer objects in a seperate package?


    The idea is to set the code up in a such a way so that if another developer comes along to my codebase they cannot set the record number in the client code by simply creating an instance of the Room class and using the accessor methods. My solution achieves this. So problem solved

    If someone moves it to another package is not relevant - of course it will break my package access, you've just moved it to a different package, that's how package access works . Same argument if you change a private member to public - is that an argument for not making something private in the first place, simply because someone can change it to public, nope.

    Roel De Nijs wrote:And I'm quiet sure that with using reflection I can easily invoke your protected setter (or just set the record number through the Field reference).


    If I am understanding correctly, the point here is that package protection is useless because it can be got around with reflection. I don't really think this is an argument against using package protection. I think most would agree.

    Roel De Nijs wrote:Or I can do easily something like this (no hacking, just a bit of OO):



    That wouldn't work in the scenario I described - you would be creating MyRoomTO in a different package to the original Room class so you wouldn't have access to the setRecordNumber method. Plus I could make the class final to prevent it being subclassed.

    So, under normal usage the solution proposed would allow me to

    1) Set the record number of the Room object in my Business class.
    2) Allow someone using the client code to create a Room object, but it would prevent them from setting the record number.

    Overall I think this is a better solution than exposing all members of the class as it conveys the correct intention in code. It conveys that the designer did not want someone in the client package setting the record number. Whereas the solution where you expose all the members as public conveys that it is OK and you support setting the record number in the client package when it is meaningless to do so and not your intention.
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:Plus I could make the class final to prevent it being subclassed.


    That would be the only possible (and working) solution, because I can easily put MyRoomTO in the same package as RoomTO.

    Sean Keane wrote:Whereas the solution where you expose all the members as public conveys that it is OK and you support setting the record number in the client package when it is meaningless to do so and not your intention.


    That's simply what you get if you don't want to use getters/setters. And I prefer getting the cleaner code above taking some actions to prevent a record number from being set at the client (while because the record number is in the RoomTO object a developer will be able to set it with some extra code).
     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

    Sean Keane wrote:Plus I could make the class final to prevent it being subclassed.


    That would be the only possible (and working) solution, because I can easily put MyRoomTO in the same package as RoomTO.



    If you have your business classes and client related classes separated out into separate packages then there's no need to make the Room class final.

    A working solution in a single project setup is to put all business classes in the package suncertify.service.* and all client classes in a different package. Based on that setup there's no need for final.

    Roel De Nijs wrote:

    Sean Keane wrote:Whereas the solution where you expose all the members as public conveys that it is OK and you support setting the record number in the client package when it is meaningless to do so and not your intention.


    That's simply what you get if you don't want to use getters/setters. And I prefer getting the cleaner code above taking some actions to prevent a record number from being set at the client (while because the record number is in the RoomTO object a developer will be able to set it with some extra code).



    It's possible to set private members of a class with some extra code - does that mean you don't use private members, of course not. So I think we can leave to one side the fact that you can get around package protection via reflection to one side - it's not an argument against using package protection.

    Encapsulation is always a good design philosophy to follow and that is what I am doing with only allowing the class that should be allowed set the record number to set it.

    The benefit you feel you get by exposing the record number is the code is cleaner. But if you look at the two example below, they both look just as clean

    So the solution that I am proposing has a real added benefit of not allowing or conveying in code that it is ok or supported to set the record number in the client code - this is not a subjective benefit.

    The solution of exposing all members of the Room class as public on the other hand has no real added benefit, and the argument for it is that it gives you cleaner code. This is a subjective benefit - and it doesn't appear cleaner to me. You have to write just as many lines of code. All you are saving is 5 characters per line.
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Sean Keane wrote:If you have your business classes and client related classes separated out into separate packages then there's no need to make the Room class final.

    A working solution in a single project setup is to put all business classes in the package suncertify.service.* and all client classes in a different package. Based on that setup there's no need for final.


    If you don't make it final, I'll subclass it and will be able to invoke record number. Creating a suncertify.service package client-side and putting MyRoomTO in there, will do the trick (unless it's final).

    And as a final note: at the client I'm working for we are developing an application, based on a custom developed API (framework) and we also try to hide/encapsulate methods/classes (marking them as private, protected, package private, final) to ensure the users get a consistent look-and-feel throughout the desktop application. And because the framework is just used by this company, no other developer uses reflection to invoke some "hidden" method. That would be quickly noticed by another developer and he would certainly be charged with that code.
    We also use a transfer object and our setId-method is publicly available and although you would expect it only makes sense to be invoked server side, we also have a few invocations client-side. And that's just what I tried to say: when you develop an API you should be very careful when to (dis)allow a certain method call, certainly when you develop an API which will be used by 3rd parties (if it's just for internal use only, you simply make the necessary change and you're done).

     
    Sean Keane
    Ranch Hand
    Posts: 590
    Eclipse IDE Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The key point is the benefit of not allowing the code in the client package set the record number. The solution I proposed achieves this. It allows me set the record number in the Business service class and prevents classes in the client package from setting the record number.

    Using my current project setup, if I don't set the Room class as final, then someone will have to create a subclass in the exact same package as my Room class in order to change the behaviour. But as I already mentioned, if I am worried about it being subclassed I can simply mark the class as final.

    The solution works and has benefits over exposing all members of the class. Whereas the solution to expose all members has no clear benefits that I can see, other than a subjective one of providing cleaner code - which it doesn't appear to me to be any cleaner from the example I gave in my previous post.

    Overall I think this solution of using getters\setters, where the setter for the record number is package private in the service package, is a more favourable solution with the most benefits. So I reckon I will go with that.

     
    reply
      Bookmark Topic Watch Topic
    • New Topic