I have a Util class and there is a static method called csvToEmployees. In order to use this method with different type of request classes, I am trying to convert the class as shown below that takes generic parameter:
public class CsvHelper<T> {
public List<T> csvToEmployees(InputStream is) {
//code omitted
for (CSVRecord rec : records) {
T employee = new T(
// ...
);
employees.add(employee);
}
return employees;
}
}
I call this method from my service by injecting this util class as shown below:
#Service
#RequiredArgsConstructor
public class EmployeeService {
private final EmployeeRepository employeeRepository;
private final CsvHelper<EmployeeRequest> helper;
public void create(MultipartFile file) {
List<Employee> employees = helper.csvToEmployees(file.getInputStream()).stream()
.map(EmployeeRequestMapper::mapToEntity)
.toList();
// ...
}
}
My problems are:
1. Is the implementation approach above is ok or not? I mean assuming that there are different kind of requests with the same fields, is using generic with that approach ok?
2. I get "Type parameter 'T' cannot be instantiated directly" error in the T employee = new T( line of util class. How can I fix it?
The best solution, in my opinion, is just creating multiple csvToObject methods inside the classes that you need to process.
I mean if you already know that you’re transforming a stream into a list of employees (it’s “hard coded” in the service method) why would you need to use generics? Just use the method for employees instead.
Related
I have a class which calls two singleton classes FirstClass and SecondClass as below. Is there a way to access the data computed in FirstClass in the SecondClass. In this case I don't want to make external service call in second class since the first class has already called it. Instead, just use the data (stored in first class function) in the second data function. What are the ways to do it in Spring Framework?
public class CallingFunction() {
List<String> generateData() {
return Lists.newArrayList(new FirstClass(), new SecondClass())
}
#Singleton
public class FirstClass() extends interface {
public String function() {
//operations. This function calls multiple services and stores ouput to hashMap
Map<String, String> hashedData = Maps.newHashMap();
hashedData.put(dataFromAnotherService);
return hashedData.get("abc");
}
}
#Singleton
public class SecondClass() extends interface {
public String function() {
//Use hashedData here instead of invoking the service again.
//Other operations
return "data";
}
}
Pass a reference of FirstClass to SecondClass, either by having Spring do it for you (which is an I.o.C. container is for) or do it explicitly in generateData.
i want to exclude specific properties of spring rest response body. after hours of googling around i found this: http://www.jroller.com/RickHigh/entry/filtering_json_feeds_from_spring due to its date i like to ask if there is something more up-to-date for jackson and or fasterxml. JsonView doesnt fit my requirements as i need to have such case covered:
if A is the set of all my attributes: one time i need to expose B with B ⊂ A. another time C with C ⊂ A. And B ∩ C != ∅
this would cause complex view declarations as well as annotating every class and might not be possible as well in some cases. so what i would like to do is something similar to this:
#RequestMapping("/test1")
#JsonIgnoreProperties( { "property1"})
public TestObject test1(HttpRequest request){
return new TestObject();
}
#RequestMapping("/test2")
#JsonIgnoreProperties( { "property2"})
public TestObject test1(HttpRequest request){
return new TestObject();
}
with output:
{property2:ipsum,property3:dolor}
{property1:lorem,property3:dolor}
In my opinion Jackson View is what you need.
You have to define three interfaces which should cover all properties:
Public - all common properties.
A - properties which belong to set A.
B - properties which belong to set B.
Example interfaces:
class Views {
static class Public { }
static class A extends Public { }
static class B extends Public { }
}
Assume that your POJO class looks like this:
class TestObject {
#JsonView(Views.A.class) String property1;
#JsonView(Views.B.class) String property2;
#JsonView(Views.Public.class) String property3;
}
Now, your controller should contain below methods with annotations:
#RequestMapping("/test1")
#JsonView(Views.B.class)
public TestObject test1(HttpRequest request){
return new TestObject();
}
#RequestMapping("/test2")
#JsonView(Views.A.class)
public TestObject test2(HttpRequest request){
return new TestObject();
}
All of this I has created without testing. Only by reading documentation but it should work for you. I am sure that similar solution worked for me once.
I've got around 5 objects that I want to do similar things with.
I figured out that not to polute the code I will put a logic for those objects in one place.
public class MetaObjectController<T extends MetaObject> {
#Autowired
private final MetaObjectRepository<T> repository;
// generic logic
Here's how repository looks:
public interface MetaObjectRepository<T extends MetaObject> extends GraphRepository<T> {
T findByName(String name);
}
Now, I create concrete class which uses delegation:
public class ExperimentalController {
#Autowired
private final MetaObjectController<MetaCategory> metaController;
#RequestMapping(method = RequestMethod.POST)
public void add(#RequestBody MetaCategory toAdd) {
metaController.add(toAdd);
}
Now, when I look at the generated queries I see, that although instantiated correctly, repository puts MetaObject as an entity name instead of runtime type.
Is there a way to force the repository to use runtime type?
Please don't advise to put a #Query annnotation. That's not what I am looking for.
This is most probably due to type erasure: at runtime there is only the type constraint available which is MetaObject. If you want to use (via spring-data) the actually relevant subclass you will have to create explicit interfaces of the MetaObjectRepository like this:
public class Transmogrifier extends MetaObject
public interface MetaTransmogrifierRepository
extends MetaObjectRepository<Transmogrifier> {}
I got the following problem. I want to create SomeObject. This object consists of various nested objects NestedObject1, NestedObject2, ... I created mappers to create those nested objects Mapper1 to create NestedObject1, Mapper2 to create NestedObject2, and so on. Those Mappers call a huge amount of setters, and some of them need information from some entites from the db (and some don't). This is the problem in the java language:
public class MyClass {
#Inject
private MyDao dao;
#Inject
private Mapper1 mapper1;
#Inject
private Mapper2 mapper2;
#Inject
private Mapper3 mapper3;
#Inject
private Mapper4 mapper4;
#Inject
private Mapper5 mapper5;
public SomeObject map(Integer id) {
SomeEntity entity = dao.findById(id);
SomeObject someObject = new SomeObject();
someObject.setNestedObject1(mapper1.map(entity));
someObject.setNestedObject2(mapper2.map());
someObject.setNestedObject3(mapper3.map(entity));
someObject.setNestedObject4(mapper4.map(entity));
someObject.setNestedObject5(mapper5.map());
return someObject;
}
}
I am thinking of the following refactoring:
Make an interface Mapper and have all mappers implement this. Then I could inject the List of mappers. It would be pretty easy to add or remove on mapper, without touching MyClass. I think this is a good idea but the problem is the MyDao. Instead of one DB access I would then need 3.
The interface would then look like
public interface Mapper {
public void map(SomeObject someObject);
}
Mapper1 would look like
public class Mapper1 implements Mapper {
private static final Integer VALUTA = 1;
#Inject
private MyDao dao;
#Override
public void map(SomeObject someObject) {
SomeEntity entity = dao.findById(id); // and I have no idea what the id is
NestedObject1 nestedObject1 = new NestedObject1();
nestedObject1.setSomeField(entity.getSomething());
nestedObject1.setSomeOtherField(VALUTA);
someObject.setNestedObject1(nestedObject1);
}
}
id is unknown in this context. Include id in the signature? I have no idea...
Mapper3 and Mapper4 would have to look up the entity as well.
I was thinking about an abstract class which will look for the entity in the BeforeClass method, but I think this still get's called multiple times.
Btw: I know the title sucks, please feel free to rename it.
I have a base class, Record, that represents records in a database. I have Customer and Job classes that extend record. I've never used annotations before but what i think i would like to do is create a custom annotation and mark a method in my Customer class that return its Jobs objects so i know to save the Jobs objects to the database when i save the Customer.
Something like this
class Record{
private int id;
public void save(){
//look up all methods in the current object that are marked as #alsoSaveList,
//call those methods, and save them as well.
//look up all methods in the current object that are marked as #alsoSaveRecord,
//call those methods, and save the returned Record.
}
}
class Customer extends Record{
#alsoSaveList
public List<Job> jobs(){
return list of all of customers jobs objects;
}
}
class Job extends Record{
#alsoSaveRecord
public Customer customer(){
return its customer object;
}
}
Is this possible? can someone point me in the right direction?
I agree, typically if your using an ORM then you could let JPA or Hibernate deal with this. However if you want a programatic response like your mentioning here's a simple example based :
Define your Annotation: AlsoSaveRecord.class
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface AlsoSaveRecord {
// The record class type
Class<?> value();
}
Code to find methods to invoke: Code you could add to your class example above
public void save() {
List<Method> toSaveRecords = findMethodsAnnotatedWith(AlsoSaveRecord.class, obj);
for (Method rec : toSaveRecords) {
AlsoSaveRecord anno = rec.getAnnotation(AlsoSaveRecord.class);
Class<?> recordType = anno.value();
Object objToSave = rec.invoke(obj);
}
}
List<Method> findMethodsAnnotatedWith(Class<? extends Annotation> annotation, Object instance)
{
Method[] methods = instance.getClass().getDeclaredMethods();
List<Method> result = new ArrayList<Method>();
for (Method m : methods) {
if (m.isAnnotationPresent(annotation)) {
result.add(m);
}
}
return result;
}
The above will scan for AlsoSaveRecord annotations in the Object in hand and return any applicable methods. You can then invoke those methods returned which were of a result of being annotated. The invoke will return the Object which you can cast or do something with.
Edited as requested to have the "Record Type" defined within the annotation (ie. #AlsoSaveRecord(MyRecord.class);
The method above can now grab the recordType which is the defined class when annotated