If you create a REST service that serves Banana objects, there are likely two different conceptual models of those bananas.
What is used on the REST API you serve to the public
What is used internally to the application, with possible DB fields that aren't exposed externally
One might reflect this reality in code by having two classes, with conversions between them:
class Banana {
private String color;
}
class InternalBanana {
private int id;
private String color;
private ZonedDateTime createdAt;
public toBanana() {
return new Banana(color);
}
}
Pros:
Marshalling to Json via jackson is simple
Banana can be used while test-driving the API code
Cons:
Code duplication
Converters of internal objects need to be updated any time the API is updated
So what if we merge the two classes:
class Banana {
private int id;
private String color;
private ZonedDateTime createdAt;
public String toApiJson() { ... }
}
Pros:
No duplication
Seems more robust to changes in the public API
Cons:
No model of REST API objects
Marshaling to Json requires special code
Internal fields will often be null
Which approach is likely to be the most efficient over the lifetime of a given service?
Related
My task
Force two classes to have the same (or similar) field names (and their types)
Description
I have an entity and Data Transfer Objects (DTO).
How do I force that if someone adds / removes / changes a field in entity, a test will fail, so DTO class matches the entity class by fields names and if possible by fields structure.
class City {
private String name;
private CityDetails cityDetails;
private Mayor mayor;
}
class Mayor {
private String name;
private LocalDate electionFrom;
private LocalDate electionTo;
}
class CityDto {
private String name;
private CityDetailsDto cityDetails;
private MayorDto mayor;
}
class MayorDto {
private String name;
// The client of the end-point of such DTO does not care about the mayor election.
}
CityDetails and CityDetailsDto can be different or not necessary. I would like to have their diff.
Approaches
Using so called diff tool
Let's imagine a diff tool which has input parameters - two objects and output parameter - Map, where Diff is a structure oldValue, newValue. This tool returns difference between input arguments.
public Map<String, Diff> diff(final Object first, final Object second) {
// This is implemented.
return innerDiff(first, second, otherParameters); //
}
public class Diff {
private String oldValue;
private String newValue;
// getters, setters, constructor.
}
// To achieve this, we used Guava Plain map. It works well!
How do I achieve the same for classes. I want to diff two classes and have their fields as difference.
public Map<String, FieldDiff> diff(Class<?> type1, Class<?> type2) {
// How?
}
One idea is to use reflection and iterate though all fields of the class.
How about using toString and compare?
As an alternative, we define toString() methods in both and then compare.
How to do that if some fields are missing?
Serialize into JSON
Similar to the previous one, but serializing both objects into JSON and then compare their classes by json field names. However, if our entity have already annotation DoNotSerializeNulls with is equal to #JsonInclude(JsonInclude.Include.NON_NULL) #JsonIgnoreProperties(ignoreUnknown = true), then how to do that?
References
https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
I was reading this answer on SESE about encapsulation and getters/setters. Suppose I favor the use of immutable classes, so if a setter were implemented, it would return the a new object reflecting the change, for example:
//return a new Book reflecting the price change.
public Book updatePrice(double price){}
In the link, the answer suggested I have a method called getDisplayinformation() that returns a data structure.
(think an array indexed by an enum, a struct, or a methodless class)
Following this advice how would I return a Book with a List of authors?
public final class Author{
private final String id;
private final String firstname;
private final String lastname;
//Constructor
}
public final class Book{
private String bookID;
private final String title;
private List<Author> authorsList;
private double price;
//Constructor
}
Suppose I wanted to return a Map<String,String>.
public Map<String,String> getDisplayinformation(){
Map<String,String> displayMap = new HashMap<String,String>();
display.put("BookTitle", title);
display.put("ID", bookID);
display.put("Price", price.toString())
//insert authorsList;
return displayMap;
}
The answer you quote got half of it right. Providing getters for fields does break encapsulation, because it makes the caller dependent on some internal structure.
Now, returning a map where the caller needs to know the keys and knows what that information is, is basically not different than providing a getter for that field.
Object-orientation tries to tell us that the functionality needs to be bundled with the data. So, the Book has to have some method to present the Book. I would not call it getDisplayInformation(), rather simply display(). It can return something, and it can take relevant parameters too.
The point is, that anything returned by display() must be about the presentation, and must not be about the book. Semantics about being a book should be lost at that point, otherwise the caller will be tightly coupled.
So, it's ok to return an XML document, JSON document, HTML, a Wicket Component, whatever it is you can use for presentation that is independent of the Book.
Or, the method could take an argument to present itself to. Like AWT Component.paint(Graphics g) or something.
Note: this is actually a controversial subject. Mixed-paradigm development (a mix of procedural and ood) would argue that presentation needs to be separated from objects, while object-orientation argues that data and function belong always together.
I have a question about OOP implementation and design patterns.
I have a fixed class model which I cannot change (because it is generated automatically each time the application starts). There are many classes there with equals fields like in example below: as you can see the fields city and streets are contained in the both classes.
public class A{
String city;
String street;
String name;
....//get methods
}
public class B{
String city;
String street;
String age;
....//get methods
}
I need to extract an address form the both types of classes and I want to implement it with one method (because it seems to be silly to write the same code twice). If the class model were changeable, I could add a new interface Addressable which A and B could implement.
public interface Addressable{
public String getStreet();
public String getCity();
}
//somewhere in code
public Address getAddress(Addressable addressable){
return new Address(addressable.getCity(), addressable.getStreet());
}
What is the most elegant way to implement the same without interface and without coding the same for different classes?
If you are not able to change A or B, you would have necessarily a degraded solution.
A simple and good designed solution would rely of course on a interface defining an Address retrieval method (Address getAddress()) that A and B would implement.
You could also define a wrapper class :
public class WrapperA implements Addressable {
private final A a;
public WrapperA(A a) {
this.a = a;
}
#Override
public Address getAddress(){
return new Address(a.getCity(), a.getStreet(), etc...);
}
}
But it may be rather clumsy if you have to duplicate this kind code for many classes.
Besides the client will not manipulate any longer a A but a WrapperA class.
It may break the actual client code.
So also here, an interface is required if you want to implement a real adapter.
As said, without redesigning a minimum A or B, a really good solution is complicated.
As workaround, you may define an Address class that provides factory methods to create Address from a A or a B instance.
public class Address{
...
String city;
String street;
...
private Address(){
}
public static Address of(A a){
return new Address(a.getStreet(), a.getCity(), ....);
}
public static Address of(B b){
return new Address(b.getStreet(), b.getCity(), ...);
}
}
Then use these methods to create the Address on the demand as you need it.
You could write adapters to provide a common interface.
public class AdpaterA implements Addressable {
private final A a;
public AdapterA(A a) {
this.a = a;
}
#Override public String getStreet() {
return this.a.street;
}
// other method is omitted as homework ;-)
}
Then you would use the adapter classes for further processing.
I had a similar situation, where classes are generated during the build process. (In my case, the build process would inspect the database, and generate one class per database table, with all the fields.)
You state that the classes are generated when your application starts. In case they are generated during the build process, you can add an extra element to the build process which alters the genreated files. In my case our build servers were only Linux, so I added a sed line to our ant script.
I have been doing Java for 12 years, and I have recently been doing Javascript, and I was wondering if the Java community has considered some kind of flexible constructor mechanism.
Things can get messy with constructors in Java. If there are many different pathways to create an object, then you need a constructor for each.
What if you could have a constructor where you can put in whatever values you like that would match up with a classes internal field :
Person p = new Person([
name:’bob’,
height:123,
address:new Address([
street:’asdf’,
postcode:4232
])
]);
(I am using square brackets here, but you would need some other symbol, as this would conflict with arrays in Java)
Then you define which fields in a class may be used in a constructor combination with an annotation :
public class Person{
#constructable
private String name;
#constructable
private int height;
#constructable
Private Address address;
.....
}
public class Address {
#constructable
private String street;
#constructable
private String postcode;
#constructable
private String city;
.....
}
This would all be syntactic sugar. During compile time, the compiler would work out all the constructors that are needed for a class and update the class accordingly.
Has anything like this ever been proposed a JSR?
Does this break any core philosophy behind Java? (Ie. Constructors should not be so unrestrictive)
This can mostly be achieved by the Builder pattern. This is useful when there is a lot of information required to create the object.
While creating a Web service I decided to exchange Business Object (BO) between client and web service.
If in the future I get a request to expand my model and put some new attributes (field) in my BO and send it to the client, what would be the best approach?
So basically, each BO may have 0..n meta-fields.
Each meta-field is Key,Value like, where keys can be anything from simple data types to other BOs.
Here is a little Java code for modelling BOs, I just need confirmation that I'm on the right track.
class AbstractBO{
//optional list of meta fields for future extension
List<MetaField> metaFieldList;
//setters. getters
}
----
class MetaField {
private Object key;
private Object value;
// setters
// getters
}
----
class MyBO extends AbstractBO {
//BO specific fields
private String name;
...
}
---
TODAY
class Person extends AbstractBO {
private String name;
private int age;
//extend metaFieldList = null;
}
----
TOMORROW
class Person extends AbstractBO {
private String name;
private int age;
//list with new metafield
}
How to model Person for Tomorrow purposes?
If, as your follow-up comment implies, you actually want to send the direct object code (presumably by implementing Serializable) instead of using a XML or JSON (which is what you'd typically do when implementing a web service), then I don't know how you'd actually be able to achieve what you want.
When Java tries to recreate your object by deserializing it, it will have to match the input data against what it believes the class to be. For best practice purposes, you should be implementing serialVersionUID and changing it each time you modify your class so that when you add variables, the person on the other end won't be able to erroneously reconstruct the class that you send them if they have an old version of the code.