Search code examples
javagenericsinheritancefactory-pattern

How to create child object from parent one assigning some fields


I am a newbie in Java and would like to gather some ideas, because I stucked.

I have some parent class, let's say

@Data
public class Person implements Hometown {
    private String name;
    private Country motherland;
}

An interface:

public interface Hometown {     
    Country getMotherland(); 
}

And some child classes:

@Data
public class Norwegian extends Person {  
    //motherland should be "Norway"
    ..
}

@Data
public class Portuguese extends Person {
    //motherland should be "Portugal"  
    ..
}

Via RestClient I can receive Person class:

public interface PopulationInfoClient {

    @GET
    @Path("/people/{personId}")
    Person search(@PathParam("personId") String personId);

}

After I received the person information I want to set them a hometown in my service. And then return a child class of generic type (can be Norwegian, Portuguese, etc).

@Inject
@RestClient
PopulationInfoClient populationInfoClient;

public T getCitizen(String personId) {
    Person person = this.populationInfoClient.search(personId);
    ...
    return ...
}

The question is how can I create child classes like Norwegien with motherland set to "Norway" using generics? And return them within my service function getCitizen()?

I would be thankful for the answers and ideas

I tried to use Factory pattern, but failed


Solution

  • Well, I think you can use a custom generic factory method.

    Interface:

    public interface PersonFactory<T extends Person> {
        T create(Person person, Country motherland);
    }
    

    Implementation:

    public class NorwegianFactory implements PersonFactory<Norwegian> {
        
        @Override
        public Norwegian create(Person person, Country motherland) {
            Norwegian norwegian = new Norwegian();
            norwegian.setName(person.getName());
            norwegian.setMotherland(motherland);
            return norwegian;
        }
    }
    

    Your updated code:

    @Inject
    @RestClient
    PopulationInfoClient populationInfoClient;
    
    @Inject
    private Map<String, PersonFactory> personFactories;
    
    public T getCitizen(String personId, Country motherland) {
        Person person = this.populationInfoClient.search(personId);
    
        PersonFactory <T> personFactory = personFactories.get(motherland.getName());
        if (personFactory == null) {
            throw new IllegalArgumentException("Unknown motherland is " + motherland.getName());
        }
    
        return personFactory.create(person, motherland);
    }