4

I am new to Java and I am coding up a modular application made like this:

*************          *******         ***********
*           *          *     *         *   Data  *
* Front-end * -------- * API * ------- * Handler *
*           *          *     *         *         *
*************          *******         ***********

Essentially, I want to be able to define an API with N classes, and then have a "Data Handler" module deal with storing the objects somewhere (a database, for example), without the front-end needing to know anything of how that is implemented.

So, let's say I have two classes defined in my API: Contract and Company. I want the front-end to be able to do something like:

myContract = new Contract();
myCompany = new Company();
myContract.setCompany(myCompany);
myContract.save();
myCompany.save();

This way, in the future I could change the way I store the data (the Data Handler module), without changing any code in the front-end.

To do this, I wrote two interfaces for Contract and Company in the API module. Then, in the data handler module I wrote to classes which implement the two interfaces: DbContract and DbCompany.

Now, I am running into issues because I have defined the getter/setter methods in the Contract interface as:

public interface Contract {
    public Company getCompany();
    public void setCompany(Company company);
}

And implemented them in DbContract as:

public class DbContract implements Contract {
    private DbCompany company;

    @Override
    public Company getCompany() {
        return this.company;
    }

    @Override
    public void setCompany(Company company) {
        this.company = company;
    }
}

However, I am getting class type mismatch errors all over the place... Am I completely missing the point? How should I actually do this?

Thanks in advance for your help.

9
  • 1
    In setCompany, you can't assign a Company to a DBCompany reference without doing a cast. When / how are you creating a DBCompany?
    – BretC
    Commented Apr 24, 2015 at 11:06
  • My idea was to have a class in the API called Manager that has methods to instantiate and return objects. Something like public Contract createContract() { return new DbContract(); } . Are casts the right way to go about this?
    – nzapponi
    Commented Apr 24, 2015 at 11:09
  • 1
    The main purpose of your API is to hide implementation details, making Frontend operate only with interfaces. By creating objects there, you break this rule. Commented Apr 24, 2015 at 11:13
  • 1
    Thank you @SashaSalauyou, how would you go about it?
    – nzapponi
    Commented Apr 24, 2015 at 11:15
  • 1
    Could you provide an example, please? As I said, I literally started coding in Java last week and I'm still a bit lost. Thanks for the help!
    – nzapponi
    Commented Apr 24, 2015 at 11:19

2 Answers 2

2

Change

    private DbCompany company;

To

    private Company company;

And every thing should be sweet.

Otherwise you will need the front end to know what type of company you are dealing with and go generic. This has not been compiled But something like:

public interface Contract<T extends Company>{
    public T getCompany();
    public void setCompany(T company);
}

public class DbContract implements Contract<DbCompany> {
    private DbCompany company;

    @Override
    public DbCompany getCompany() {
        return this.company;
    }

    @Override
    public void setCompany(DbCompany company) {
        this.company = company;
    } 
}
2
  • Thanks for the reply. The first approach was what I was initially following, however I am using JPA with EclipseLink to store the objects in a database, so I need the types to be correct (as they are defined as entities).
    – nzapponi
    Commented Apr 24, 2015 at 11:13
  • You need to look at your architecture a bit as I would agree with @Thomas that the front end should preferably not know what type of object it is using. The first option works if your data handler is enhanced with methods to createNewCompany and createNewContract.
    – redge
    Commented Apr 24, 2015 at 11:18
1
myContract = new Contract();

This wouldn't work since you can't create instances of an interface.

You seem to have the right idea, but there also seems to be a misconception on the term "implementation".

If the frontend needs to create instances of those interfaces, it needs to know an implementation or provide its own. On the other hand if the frontend should not know about the implementations at all it should call the backend to create a new instance.

Besides that it might be a better design to make Contract and Company data containers and move the actual logic for saving to a service, e.g. your code would look like this:

class Contract { ... } //as before, but classes not interfaces
class Company { ... } //as before, but classes not interfaces

Creating a new contract:

Contract myContract = new Contract();
Company myCompany = new Company();
myContract.setCompany(myCompany);

contractService.save( myContract ); //assuming this would save the company as well

You could look up the service or let it be injected. For the latter have a look at Spring dependency injection.

Update:

In your comment you state that Company and Contract would be JPA entities and if I understand you correctly you don't want the frontend to have any notion that JPA is being used.

In that case you have two options:

  1. Make your objects plain POJOs and add an XML for the JPA-mapping in the backend. Then you'd treat every instance that is passed from the frontend as a detached entity.

  2. If you want to use annotations for the mapping and don't want the frontend to know about that you'd need to provide an intermediate layer (called data transfer objects = DTO) that is used by the API. Internally the backend would then translate between entities and DTOs.

4
  • Thank you for the reply. The issue with this approach is that I'd like to use JPA with EclipseLink to store the data, so each class needs to be defined as an entity. If I used this approach, then the front-end wouldn't be "storage-agnostic" anymore.
    – nzapponi
    Commented Apr 24, 2015 at 11:14
  • 1
    @NiccolòZapponi that depends. If the frontend might know about JPA it wouldn't need to know about the correct implementation (it could be Eclipse Link or Hibernate). I'll expand my answer though.
    – Thomas
    Commented Apr 24, 2015 at 11:17
  • Thanks for the update. If I wanted to follow approach #2, am I right in thinking that I should scrap at this point the interfaces in the API, use plain objects, and have them relay the data to the appropriate back-end JPA entities?
    – nzapponi
    Commented Apr 24, 2015 at 11:29
  • @NiccolòZapponi if you don't need those interfaces for something else then yes. Basically that is what we do. In the past someone decided that our architecture needed interfaces for those DTOs but we quickly figured they were not used at all and removed them alltogether.
    – Thomas
    Commented Apr 27, 2015 at 7:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.