Generic use of 2 same classes but from different packages - java

I have two same model classes,but they are in different packages.
First one is: model.my.prod.Model and second model.my.test.Model
I have also a simple mapper for this model.my.prod.Model which take a Model class as a parameter:
public class Mapper{
private static Map<Model, String> models= new HashMap<>();
static {
models.put(Model.IMAGE_JPG, MediaType.IMAGE_JPEG_VALUE);
models.put(Model.IMAGE_GIF, MediaType.IMAGE_GIF_VALUE);
}
public static String createModelMap(Model model) {
if (models.containsKey(model)) {
return models.get(model);
} else {
throw new ModelException("Exeception");
}
}
}
Now I would like to use this Mapper also for model.my.test.Model, is it possible without copy of this Mapper and change a Model package?

You can use full qualified class names. It will make your code ugly, but you will be able to use to Model classes in Mapper.
So, instead of
public static String createModelMap(Model model)
you will have two methods
public static String createModelMap(model.my.prod.Model model)
public static String createModelMap(model.my.test.Model model)
In additional I can suggest you to rename both classes with different and more meaningful names.
And, also it's a bad idea to have packages for production and testing classes, you can use default maven/gradle project structures to avoid such packages

You can use Object and explicit casting(when necessary)
public class Mapper{
// private static Map<Model, String> models= new HashMap<>();
private static Map<Object, String> models= new HashMap<>();
static {
models.put(Model.IMAGE_JPG, MediaType.IMAGE_JPEG_VALUE);
models.put(Model.IMAGE_GIF, MediaType.IMAGE_GIF_VALUE);
}
// public static String createModelMap(Model model) {
public static String createModelMap(Object model) {
if (models.containsKey(model)) {
return models.get(model);
} else {
throw new ModelException("Exeception");
}
}
}

Related

Composition or Inheritance for classes with almost similar implementations but different input and outputs for methods?

I have the following classes, which have quite similar method implementations. Only the classes' method inputs and outputs seem to be of different types. When I put it like this, it sounds like a case for inheritance, however, the fact that the inputs and outputs are different and are related to two lambdas, make me wonder if they should remain without any relationship, as one lambda cannot be thought of in place of another (To be a case for inheritance).
My first class looks like the following.
public class JobPersistenceManager {
private String jobIndexName;
private JobLambda JobLambda;
private MyDataPersistence myDataPersistence;
private DataProcessorUtils dataProcessorUtils;
private static final String JOB_ID = "jobId";
private static final String JOB_NAME = "jobName";
#Inject
public JobPersistenceManager(#Named("jobIndexName") String jobIndexName,
JobLambda JobLambda,
MyDataPersistence myDataPersistence) {
this.jobIndexName = jobIndexName;
this.JobLambda = JobLambda;
this.myDataPersistence = myDataPersistence;
createIndexIfNotExists(this.jobIndexName);
}
public SearchDocumentResult searchJob(MyJobInput myJobInput) throws IOException {
return myDataPersistence
.searchDocument(this.jobIndexName,
dataProcessorUtils.transformObjectDataPayloadToMap(myJobInput));
}
public MyJobOutput invokeCreateJobLambdaAndIndexData(final MyJobInput myJobInput)
throws IOException {
String personRequestPayload = dataProcessorUtils.transformObjectDataInputJson(myJobInput);
Map<String, String> createdJobOutput = this.JobLambda.invokeLambda(personRequestPayload);
this.indexCreatedJob(myJobInput, createdPersonOutput);
return MyJobOutput.builder().withJobID(createdJobOutput.get(JOB_ID))
.withJobName(createdJobOutput.get(JOB_NAME)).build();
}
public int indexCreatedJob(final MyJobInput myJobInput,
final Map<String, String> createdJobOutput) throws IOException {
myJobInput = modifyJobInput(myJobInput);
String documentToIndex = dataProcessorUtils.transformObjectDataInputJson(myJobInput);
return myDataPersistence.indexDocument(this.jobIndexName, documentToIndex);
}
private void createIndexIfNotExists(final String indexName) {
if (!myDataPersistence.doesIndexExist(indexName)) {
myDataPersistence.createIndex(CreateIndexInput.builder().indexName(indexName).build());
}
}
}
My second class looks like the following.
public class EmployeePersistenceManager {
private EmployeeLambda employeeLambda;
private MyTestDataPersistence myTestDataPersistence;
private DataProcessorUtils dataProcessorUtils;
private String employeeIndexName;
private static final String PERSON_ID_KEY = "personId";
private static final String PERSON_NAME_KEY = "personName";
#Inject
public EmployeePersistenceManager(#Named("employeeIndexName") String employeeIndexName,
EmployeeLambda employeeLambda,
MyTestDataPersistence myTestDataPersistence,
DataProcessorUtils dataProcessorUtils) {
this.employeeIndexName = employeeIndexName;
this.employeeLambda = employeeLambda;
this.myTestDataPersistence = myTestDataPersistence;
this.dataProcessorUtils = dataProcessorUtils;
createIndexIfNotExists(employeeIndexName);
}
public SearchDocumentResult searchPerson(EmployeeInput employeeInput) throws IOException {
return myTestDataPersistence
.searchDocument(employeeIndexName,
dataProcessorUtils.transformObjectDataPayloadToMap(employeeInput));
}
public EmployeeOutput invokeCreatePersonLambdaAndIndexData(final EmployeeInput employeeInput)
throws IOException {
String personRequestPayload = dataProcessorUtils.transformObjectDataInputJson(employeeInput);
Map<String, String> createdPersonOutput = this.employeeLambda.invokeLambda(personRequestPayload);
this.indexCreatedEmployee(employeeInput, createdPersonOutput);
return EmployeeOutput.builder().withPersonId(createdPersonOutput.get(PERSON_ID_KEY))
.withPersonName(createdPersonOutput.get(PERSON_NAME_KEY)).build();
}
public int indexCreatedEmployee(final EmployeeInput employeeInput,
final Map<String, String> createdPersonOutput) throws IOException {
employeeInput = modifyEmployeeInput(employeeInput);
String documentToIndex = dataProcessorUtils.transformObjectDataInputJson(employeeInput);
return myTestDataPersistence.indexDocument(this.employeeIndexName, documentToIndex);
}
public Map.Entry<String, Map<String, String>> invokeLambda(final String payload) {
return new AbstractMap.SimpleEntry<>(payload, this.employeeLambda.invokeLambda(payload));
}
private void createIndexIfNotExists(final String indexName) {
if (!myTestDataPersistence.doesIndexExist(indexName)) {
myTestDataPersistence.createIndex(CreateIndexInput.builder().indexName(indexName).build());
}
}
}
As you can see, the methods perform almost the same actions. Only the indexCreatedEmployee and indexCreatedJob methods from the classes have an extra step of processing the input.
Should I keep these classes as they are now without any relationships between them, or should I create an abstract persistence manager class and perform the following.
Move createIndexIfNotExists to the abstract class
Create abstract methods search(), invokeLambda() and indexCreatedData() methods and implement them in each child class. The data types MyJobInput and MyEmployeeInput are POJO classes that don't have any relationship. So I guess these methods I mentioned would then take "Object" parameters?
EmployeeLambda and JobLambda are again classes with no relationship between them. Another concern I had towards creating some sort of inheritance was that, Employee Lambda and JobLambda cannot be used inter-changeably. So was wondering if they should inherit the same parent class just because they're both lambda classes.
OR is there another way to go about this? Any advice would be much appreciated. Thank you very much in advance.
As promised yesterday, here is what I would do.
Create a Lambda interface and make JobLambda and EmployeeLambda implement it
public interface Lambda {
Map<String, String> invokeLambda(String payload);
}
public class JobLambda implements Lambda {
//... your implementation
}
public class EmployeeLambda implements Lambda {
//... your implementation
}
Do the same for DataPersistence
public interface DataPersistence {
boolean doesIndexExist(String indexName);
void createIndex(CreateIndexInput createIndexInput);
int indexDocument(String indexName, String documentToIndex);
SearchDocumentResult searchDocument(String indexName, Map<String, String> payloadMap);
}
public class MyDataPersistence implements DataPersistence {
//... your implementation
}
public class MyTestDataPersistence implements DataPersistence {
//... your implementation
}
Then create a parent class PersistenceManager which contains all the duplicated methods, parametrized for the type of input/output:
(Note: I didn't complete everything, but I did something just to make you understand the concept)
public class PersistenceManager<I, O> {
protected static final String ID = "Id";
protected static final String NAME = "Name";
private String indexName;
private Lambda lambda;
private DataPersistence dataPersistence;
private DataProcessorUtils dataProcessorUtils;
public PersistenceManager(String indexName, Lambda lambda, DataPersistence dataPersistence, DataProcessorUtils dataProcessorUtils) {
this.indexName = indexName;
this.lambda = lambda;
this.dataPersistence = dataPersistence;
this.dataProcessorUtils = dataProcessorUtils;
createIndexIfNotExists(indexName);
}
public SearchDocumentResult search(I input) {
return dataPersistence.searchDocument(indexName, dataProcessorUtils.transformObjectDataPayloadToMap(input));
}
public O invokeCreateLambdaAndIndexData(final I input) {
String requestPayload = dataProcessorUtils.transformObjectDataInputJson(input);
Map<String, String> createdOutput = this.lambda.invokeLambda(requestPayload);
//continue generalizing following the same logic
}
public int indexCreated(I input, Map<String, String> createdOutput) {
//continue generalizing following the same logic
}
private void createIndexIfNotExists(final String indexName) {
if (!dataPersistence.doesIndexExist(indexName)) {
dataPersistence.createIndex(CreateIndexInput.builder().indexName(indexName).build());
}
}
}
At this point, you can specialize your classes by simply choosing the parameters
... all the rest of the code will be shared in the parent class.
public class JobPersistenceManager extends PersistenceManager<MyJobInput, MyJobOutput> {
private static final String JOB_ID = "Job" + ID;
private static final String JOB_NAME = "Job" + NAME;
public JobPersistenceManager(String indexName, Lambda lambda, DataPersistence dataPersistence, DataProcessorUtils dataProcessorUtils) {
super(indexName, lambda, dataPersistence, dataProcessorUtils);
}
}
public class EmployeePersistenceManager extends PersistenceManager<MyEmployeeInput, MyEmployeeOutput> {
private static final String EMPLOYEE_ID = "Employee" + ID;
private static final String EMPLOYEE_NAME = "Employee" + NAME;
public EmployeePersistenceManager(String indexName, Lambda lambda, DataPersistence dataPersistence, DataProcessorUtils dataProcessorUtils) {
super(indexName, lambda, dataPersistence, dataProcessorUtils);
}
}
... and use them like this:
PersistenceManager employeePersistenceManager = new EmployeePersistenceManager(...);
employeePersistenceManager.search(employeeInput); //<-- the code is in the base class

JAVA How can i get a method to accept a parent class and all of it's extended classes?

I apologize if this has been answered before but either i don't know the correct verbiage or my google fu is bad.
I have a TestModel class which has the getters and setters for all the tests I use. Then I have a AdditionalTestModel class that extends the TestModel with additional getters and setters for that specific type of tests.
Now I have BuildTest Class that i want to be able to pass TestModel and any extended classes of TestModel.
public static Class<?> buildTest(Class<?> test, Class<?> template)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> testClass = test.getClass();
Method[] testMethods = testClass.getMethods();
for (Method method : testMethods) {
String name = method.getName();
if (name.startsWith("get")) {
String testMethodType = method.getReturnType().getTypeName();
// additional code removed//
}
}
If instead of Class<?> i was using TestModel it would work for any test that i pass of Class type TestModel. But i want to be able to pass the extended class to this method as well without having to write a method for each extended class. Any recommendations?
Adding information on the models in case it matters.
public class TestModel {
private String testDescription;
private String testName;
private String apiPath;
private String method;
private String expectedTest;
private Map<String, String> header = new HashMap<>();
private Object body;
private String expectedResult;
private String testCaseId;
private String testUUID;
private List testTypes;
public String getTestDescription() {
return testDescription;
}
public void setTestDescription(String testDescription) {
this.testDescription = testDescription;
}
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getAPIPath() {
return apiPath;
}
public void setAPIPath(String apiPath) {
this.apiPath = apiPath;
}
public String getExpectedTest() {
return expectedTest;
}
public void setExpectedTest(String testName) {
this.expectedTest = testName;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Map<String, String> getHeader() {
return header;
}
public void setHeader(Map<String, String> header) {
this.header = header;
}
public Object getBody() {
return body;
}
public void setBody(Object body) {
this.body = body;
}
public String getExpectedResult() {
return expectedResult;
}
public void setExpectedResult(String expectedResult) {
this.expectedResult = expectedResult;
}
public String getTestCaseId() {
return testCaseId;
}
public void setTestCaseId(String testCaseId) {
this.testCaseId = testCaseId;
}
public String getTestUUID() {
return testUUID;
}
public void setTestUUID(String testUUID) {
this.testUUID = testUUID;
}
public List getTestTypes() {
return testTypes;
}
public void setTestTypes(List testTypes) {
this.testTypes = testTypes;
}
}
public class AdditionalTestModel extends TestModel {
#Override public Object getBody() {
return super.getBody();
}
}
Edit: per a request adding the call information here:
#Test(dataProvider = "Default", threadPoolSize = THREADS, timeOut = API_TIME_OUT)
#Description("")
public void sampleTest(AdditionalTestModel testFromDataProvider) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
testSetup(testFromDataProvider);
AdditionalTestModel test = BuildTest.buildTest(testFromDataProvider, template);
Response response = RestAPI.call(test, testEnvironment);
if (null != response) {
ValidateAPIResponse.validateTestModel(test, response);
} else {
Assert.fail("Response is null, probably a bad method.");
}
}
Where testFromDataProvider is passed from a TestNg data provider.
Now LppEdd below already pointed out i could only assign the base class using generics so working on trying it his way, just have not gotten a chance to change things up yet.
Edit: Also realize now my question was bad. Thanks LppEdd. I should have asked How can I get a method to accept an instance of a class and an instance of any extended class
You are close, you just need to use the extends modifier.
If the class passed in as the test and template parameter should be the same exact class type, you can do:
public static <T extends TestModel> Class<T> buildTest(Class<T> test, Class<T> template) { ... }
Otherwise you can do
public static Class<? extends extends TestModel> buildTest(Class<? extends TestModel> test, Class<? extends String> extends TestModel) { ... }
Which will allow different types to be returned and passed in to each parameter.
You can read up on Java generics and wilcards starting here: https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
Your buildTest method must accept a TestModel class.
You might be looking for something like
public static TestModel buildTest(
final TestModel test,
final TestModel template) {
final Class<? extends TestModel> testClass = test.getClass();
final Method[] testMethods = testClass.getMethods();
for (final Method method : testMethods) {
final String name = method.getName();
if (name.startsWith("get")) {
final String testMethodType = method.getReturnType().getTypeName();
// additional code removed
}
}
// Maybe
return yourNewInstance; // yourNewInstance is a TestModel, or any class extending it
}
The template argument seems unused here (clarify).
What's the wanted return type? (clarify)
Usage example
final TestModel value1 = buildTest(new TestModel(), ...);
final TestModel value2 = buildTest(new AdditionalTestModel(), ...);
This looks to be exactly the same problem as must be solved by test frameworks. For example, see junit (https://junit.org/junit5/).
The core problem is how to obtain the collection of test methods of a class.
A direct solution would be to have the test class be required to answer its test methods, say, Collection<Function<Void, Void>> getTests(); This has several problems, one being that sub-classes must explicitly list their test methods, two being that sub-classes must be careful to add in the test methods from their super-class, and third, this really fits more as static behavior, which would try to shift java instance typing to the class layer, which just isn't supported by java.
An indirect solution would be to require that test methods satisfy a particular pattern (for example, must start with "test" and have no parameters), and use reflection to discover the methods. Or, use an annotation (say, #Test, which is what junit does) to mark out test methods, and again use the java reflection API to discover methods with the marker.

Make inherited method to use subclass' variables instead of superclass'

I am working on a project in Java and I decided to use MVC architecture.
I have Model class that looks like this:
public class Model {
static String table_name = null;
// ...
public static Model create(Map<String, Object> data) {
// insert `data` into database table `table_name`
}
// ...
}
I want to have class User that extends Model, but I don't want to re-implement create() in User. I just want to change value of table_name and want the inherited create() to use subclass' table_name:
public class User extends Model {
static String table_name = "users";
// ...
}
How can I achieve this?
I know a solution where I add setTableName() method to Model, but that works only if table_name is non-static. However, I need it to be static, because I want create() to be static so that I can do this: User.create().
The fact that there is a static method called 'create' on the Model class doesn't mean that there will automatically be a static 'create' method on a User class that extends the Model class - static methods belong to the class, and they're not inherited. If you implement your own 'create' method on the subclass, there's no relation between that and the 'create' method on the Model class. It sounds like you want a Factory.
If you want to stick with an approach similar to what you've done so far, something like this might work. It keeps the persistence logic in one place, while allowing each model to define its own table name and data mapping.
abstract class Model {
private PersistenceManager persistenceManager = new PersistenceManager();
abstract String getTableName();
abstract Model map(Object persistenceResult);
public void load(Map<String, Object> data) {
Object persistenceResult = persistenceManager.create(data, getTableName());
//Set appropriate fields on this class.
map(persistenceResult);
}
}
class User extends Model {
#Override
String getTableName() {
return "Users";
}
#Override
Model map(Object persistenceResult) {
//Mapping logic.
return null;
}
}
class PersistenceManager {
public Object create(Map<String, Object> data, String tableName) {
//Persistence logic.
//Return result of DB insert here.
return null;
}
}
class ModelFactory {
public static Model createModel(Class modelClass, Map<String, Object> data) {
Model model;
if (modelClass == User.class) {
model = new User();
} else {
//Cater for other models.
throw new IllegalArgumentException("Invalid model.");
}
model.load(data);
return model;
}
}
You can then use it as follows.
Map<String, Object> userData = new HashMap<>();
userData.put("name", "Bob");
Model user = ModelFactory.createModel(User.class, userData);
There is still room for cleanup in the code (like using Generics), but I'll leave that up to you.
Parent can't access child's member (and rightfully so). Look here
What you could do is created a protected method to do the task (it accepts the tablename too) and use that instead.
public class Model {
static String table_name = "A";
public static Model create(Map<String, Object> data) {
return create(data, table_name);
}
protected static Model create(Map<String, Object> data, String table_name) {
// logic here
}
}
public class User extends Model {
static String table_name = "B";
public static Model create(Map<String, Object> data) {
return create(data, table_name);
}
}

How to test file sizes with mockito in java?

I have method for which I need to create a JUnit test:
public class MyClass {
private String file1;
private String file2;
public void myMethodSpaceCheck(){
if (new File(file1).size() > new File(file2).size() {
throw new Exception .....
}
}
}
Is it possible to use Mockito to create that JUnit test?
When dealing with files in Java, my preferred option is to go with Apache VFS, as I can then treat them as any other POJO. Obviously, that's a lot of work when you are already stuck with the File API.
Another option is to forget Mockito entirely and write those files on the system. I usually avoid that, as it sometimes make it harder to have tests run in parallel on some systems.
For this specific situation, my solution is generally to provide a special class, say FileBuilder, that can instantiate new Files:
public class FileBuilder {
public java.io.File newFile(String pathname) {
return new java.io.File(pathname);
}
}
I then mock this class before passing it to MyClass, and instrument it as appropriate:
#Test(expected = Exception.class)
public void should_fail_when_file1_is_bigger_than_file2() {
FileBuilder mockFile1 = file(2L);
FileBuilder mockFile2 = file(1L);
FileBuilder mockFileBuilder = mock(FileBuilder.class);
when(mockFileBuilder.newFile("file1").thenReturn(mockFile1);
when(mockFileBuilder.newFile("file2").thenReturn(mockFile2);
new MyClass(mockFileBuilder).myMethodSpaceCheck();
}
private static File file(long length) {
File mockFile = mock(File.class);
when(mockFile.length()).thenReturn(length);
return mockFile;
}
(your example mentions File.size(); I assumed you meant File.length())
The actual implementation of MyClass would look like this:
public class MyClass {
private String file1;
private String file2;
private final FileBuilder fileBuilder;
public MyClass() {
this(new FileBuilder());
}
#VisibleForTesting
MyClass(FileBuilder fileBuilder) {
this.fileBuilder = fileBuilder;
}
public void myMethodSpaceCheck() //...
}

Force Jackson to add addional wrapping using annotations

I have the following class:
public class Message {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
When converting the instance to JSON using Jackson by default I get:
{"text":"Text"}
I would like to get:
{"message":{"text":"Text"}}
Is there any JAXB / Jackson annotation I can use to achieve my goal?
As a workaround, I can wrap my class with another class:
public class MessageWrapper {
private Message message;
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
}
or a more generic solution:
public class JsonObjectWrapper<T> {
/**
* Using a real map to allow wrapping multiple objects
*/
private Map<String, T> wrappedObjects = new HashMap<String, T>();
public JsonObjectWrapper() {
}
public JsonObjectWrapper(String name, T wrappedObject) {
this.wrappedObjects.put(name, wrappedObject);
}
#JsonAnyGetter
public Map<String, T> any() {
return wrappedObjects;
}
#JsonAnySetter
public void set(String name, T value) {
wrappedObjects.put(name, value);
}
}
Which can be used like so:
Message message = new Message();
message.setText("Text");
JsonObjectWrapper<Message> wrapper = new JsonObjectWrapper<Message>("message", message);
Is there any JAXB / Jackson annotation I can use to achieve my goal?
Thanks.
With Jackson 2.x use can use the following to enable wrapper without adding addition properties in the ObjectMapper
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
#JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
#JsonTypeName(value = "student")
public class Student {
private String name;
private String id;
}
On workaround: you don't absolutely need those getters/setters, so could just have:
public class MessageWrapper {
public Message message;
}
or perhaps add convenience constructor:
public class MessageWrapper {
public Message message;
#JsonCreator
public MessageWrapper(#JsonProperty("message") Message m) {
message = m;
}
}
There is a way to add wrapping too; with 1.9 you can use SerializationConfig.Feature.WRAP_ROOT_ELEMENT and DeserializationConfig.Feature.UNWRAP_ROOT_ELEMENT. And if you want to change the wrapper name (by default it is simply unqualified class name), you can use #JsonRootName annotation
Jackson 2.0 adds further dynamic options via ObjectReader and ObjectWriter, as well as JAX-RS annotations.
It was sad to learn that you must write custom serialization for the simple goal of wrapping a class with a labeled object. After playing around with writing a custom serializer, I concluded that the simplest solution is a generic wrapper. Here's perhaps a more simple implementation of your example above:
public final class JsonObjectWrapper {
private JsonObjectWrapper() {}
public static <E> Map<String, E> withLabel(String label, E wrappedObject) {
HashMap<String, E> map = new HashMap<String, E>();
map.put(label, wrappedObject);
return map;
}
}
Provided you don't mind the json having a capital m in message, then the simplest way to do this is to annotate your class with #JsonTypeInfo.
You would add:
#JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
public class Message {
// ...
}
to get {"Message":{"text":"Text"}}
A Simpler/Better way to do it:
#JsonRootName(value = "message")
public class Message { ...}
then use
new ObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true).writeValueAs...
If using spring, then in application.properties file add following:-
spring.jackson.serialization.WRAP_ROOT_VALUE=true
And then use #JsonRootName annotation on any of your class that you wish to serialize. e.g.
#JsonRootName("user")
public class User {
private String name;
private Integer age;
}
I have created a small jackson module that contains a #JsonWrapped annotation, that solves the problem. See here for the code: https://github.com/mwerlitz/jackson-wrapped
Your class would then look like:
public class Message {
#JsonWrapped("message")
private String text;
}

Categories