DesignPattern: Partial Object creation of unknown instance members at runtime - java

Currently I have an endpoint which returns a a fairly large data object.
This call for all objects of that type can generate 20MBs of data. However not always the clients need all the information in the object, quite often a subset of data is all that is required. I want to give the client the option to pass in some parameters to determine what parts of the object they require.
For example, specifying an array of restriction fields with each field itself a group of instance members on the object, a user can restict how much f the object they want. Looking at the figure Object below, restriction field value r1 may refer to instance members a and b.
example request "myurl/restrict=r1,r2"
MyObject(){
a;
b;
c;
d;
e;
f;
g;
h;
.... many more fields
}
So with that in mind, I created an ENUM to model the restriction fields and the subset of instance members which each instance field represents.
Now on the DB query I want to use the ENUM(s) values to decide which parts of the object I want.
So the select query will select the Object and the object can be partially instantiated by calling whatever get/set methods are required. I have implemented this on the query side by using the request params(i.e. groupings of instance members) and performing reflection on the object returned from the DB to get/set the instance fields on the object to return.
I am however, unsure if there is an already existing design pattern for this problem other than a refactor or create a new endpoints for the "lighter" objects. I dont want to argue that case, I just want to discuss for the problem at hand, is reflection a valid method of fulfilling the requirement and if not why not and what are the alternatives.
I believe this solution can cater for change easily, Only the enum needs updated if instance members change or a restriction grouping needs adapting. The rest layer or data layer requires no change. However I am unsure of the performance impact, i only implemented this today so I haven't been able to benchmark yet.
I guess the real question is; is there a design pattern for partial object creation of unknown member fields at runtime
Below is psuedo of how i implemented the select aspect below.
select(MyObj obj){
//get all the restricted fields from the request
// Instantiate new object
// for each restriction field(i.e. instance member)
// use reflection to invoke the set method of the new object(partial) passing the get method of the method argument(full object)
}

You can use object mapper for that
Employee -> name , id, uid, address
Using objectmapper readvaluetotree
Returns JsonNode/ObjectNode
Select your keys to construct the new json
Json= { "name": "xyz", "id": 101, "uid": "xoz", "address": "xqp street" }
Delete the keys which you don't need using
jsonNode.remove or delete key
then use the jsonNode to parse back to object
Employee em = objectmapper.readValue( json, Employee.class)

I think I may have found a really nice method for this task leveraging the functional aspect of Java8. Indeed this could also be implemented using an anonymous class pre Java8.
I can make use of this in the Enum and construct each one with a BiConsumer.
I can then implement that copy method while I iterate through the passed in arguments.
Now I have have the behaviour I had with reflection but without the performance impact.
public enum RestrictFields {
R1((source, target) -> {
target.setA(source.getA());
target.setB(source.getB());
target.setC(source.getC());
}),
R2((source, target) -> {
target.setD(source.D());
});
private final BiConsumer<MyObj, MyObj> copier;
private RestrictFields (final BiConsumer<MyObj, MyObj> copier) {
this.copier = copier;
}
public void copy(final MyObj source, final MyObj target){
this.copier.accept(source, target);
}
}
Now when in the select clause I can cycle through the passed Enum Values and invoke the copy method and build the restricted object based on that.
public Object select(MyObj source) {
MyObj myobj = new MyObj ();
if (!restrictedFields.isEmpty()) {
// Instead of refelction here I can use the biconsumer in the enum
for (RestrictFields field : restrictedFields) {
field.copy(source, myobj);
}
return myObj;
}
return source;
}

Related

Can you rename a variable in a generic Class?

I have got a Class PagedResult. The class is there to help me realize a JSON output with different objects in a pages format. The E is the object, that is wrapped in the List. It works all fine, but one thing still bothers me. I would like that the list with the objects does not always get the same name. I would like to adapt the name to the corresponding objects.
Class PagedResult:
public class PagedResult<E> {
Long totalItems;
Integer totalPages;
Integer currentPage;
List<E> elements;
[... Getter & Setter ...]
}
The actual JSON Output with an Object like MyPojo looks like this:
{
"totalItems": 2,
"totalPages": 1,
"currentPage": 1,
"elements": [
{
"myPojoAttr1": "hello",
"myPojoAttr2": "there"
},
{
"myPojoAttr1": "hello",
"myPojoAttr2": "folks"
}
]
}
So for each response, no matter which objects, the array is namend as "elements". I don´t want the ugly name in my JSON response, because of the changing objects in the PagedResult-class. When I get a response with objects like MyPojo the name of the JSON-Array should be "myPojos" and when I want to get a response with objects like MyWin the name "myWins".
I tried alot with #JsonProperty, but I can´t find a way, to do this "object-array-name" also generic. Can someone assist me with the problem please? Thanks in advance.
No. You can't do that. Generic types have parameters for types, not for identifiers. AFAIK, nothing in the Java language allows you to treat a Java identifier as a parameter when producing a type. (Certainly, nothing you could use in this context!)
Alternatives:
Don't do it. (Take a good hard look at your reasons for wanting the JSON attribute name to vary. What does it actually achieve? Is it worth the effort?)
Don't use a generic type. Define a different class for each kind of "paged result". (Clunky. Not recommended.)
Use a map, and populate it with a different map key for the elements attribute of each kind of "paged result". (The disadvantage is that you lose static type checking, and take a small performance and storage penalty. But these are unlikely to be significant.)
Write a custom mapper to serialize and deserialize the PagedResult as per your requirements.
For what it is worth, identifiers as parameters is the kind of thing you could do with a macro pre-processor. That Java language doesn't have standard support for that kind of thing.
Yes it's possible, using custom serializers. But even with a custom serializer you still have a problem: Generics are removed at compile time. So we need to somehow get the type during runtime.
Here is an example that will just check the type of the first element in the elements list. Definietly not the cleanest way to do it, but you don't have to adjust your PagedResult class.
public class PagedResultSerializer<T> extends JsonSerializer<PagedResult<Object>> {
#Override
public void serialize(PagedResult<Object> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeNumberField("totalItems", value.getTotalItems());
// Your other attributes
if (!value.getElements().isEmpty()) {
Object firstElement = value.getElements().get(0);
String elementsFieldName;
if (firstElement instanceof MyPojo) {
elementsFieldName = "myPojos";
} else if (firstElement instanceof MyWin) {
elementsFieldName = "myWins";
} else {
throw new IllegalArumentException("Unknown type");
}
serializers.defaultSerializeField(elementsFieldName, value.getElements(), gen);
}
gen.writeEndObject();
}
}
Now you just need to tell Jackson to use this serializer instead of the default one.
#JsonSerialize(using = PagedResultSerializer.class)
public class PagedResult<T> {
// Your code
}
Improvments: Add a Class<T> elementsType attribute to your PagedResult and use this attribute in your serializer instead of checking the first element in the list.
Another approach: use inheritance.
Have an abstract base class PagedResult that contains all the common fields, to then distinctively subclass it to PagedResultWithElements, PagedResultWithMyPojo and so on. And the subclasses contain just that "type" specific list.
As a drawback: you get some code duplication. But on the other side, you get quite more control over what happens without doing overly complicated (de)serialization based on custom code.
So, when you know the different flavors of "element types", and we talk say 3, max 5 different classes, using inheritance might be a viable solution.

Can we cast a object into a class type whose name is only known?

I have to dynamically fetch the tables whose names are available in dropdown in a jsp. Upon the selection of table name corresponding columns should be printed. For that I was running a loop in jsp and trying but is it possible to cast an object of "Object" type into a class whose class name is only known and after that using that object I have to acesss the corresponding class methods.
ex: className I got from jsp is "Book" and I have a class Book.class which has a method getName() so something like this is what I wanted:
Object obj1 = Class.forName(className).cast(obj);
obj1.getName();
Here obj is the object I have got through session.
forName takes a String and you can't call getMethod on Object because there is no such method. Ideally you'd have an interface defining the method that's common in all the types you can select from your drop down.
If that is not an option, then there is an uglier option using reflection where you don't actually need to know the type in advance:
Class<?> clazz = Class.forName("Book");
// Object obj1 = clazz.cast(obj);
// The method getName() is undefined for the type Object
Method m = clazz.getMethod("getName");
String res = (String) m.invoke(obj);
I'd not recommend using this code as is in any production application though. You'll need quite a bit of validation and exception handling in order to make this work safely.
Yes you can do that but the object must belong to that class or some of its child class else it will give you a ClassCastException. You also need to pass complete path of that class mean fully qualified class name with package.
Object obj1 = Class.forName(com.Book).cast(obj);
obj1.getName();

Bean with generic field that is not always used

This is a curious situation: I have a bean like this that store some information and I need generics, because the field "data" can contain different types of data.
public class Request<T> {
private String name;
private Integer code;
private T data;
/* Getter and setters */
}
The fact is that "data" is not always used and sometimes it can be null. And if I want to avoid raw types I have to define a type anyway, like this:
Request<Object> req = ....
Is there a better way of doing that, where I can both 1) Avoid raw types 2) Have a generic data field in my request objects ???
If you don't mind the request type, use Request<?> in your declaration.
If the request is empty (meaning there is no type, which can be set as data), declare it as Request<Void>
You could always use the Void type, e.g.
Request<Void> req = ...
or a wildcard:
Request<?> req = ...
Maybe you should consider to change object hierarhy. If you dont use data in some cases, maybe you should have two objects:
class Request {
private String name;
private Integer code;
/* Getter and setters */
}
class DataRequest<T> extends Request {
private T data;
/* Getter and setters */
}
and use:
Request req1 = new Request();
Request req2 = new DataRequest<String>();
Maybe you should think in a different way: In your case a Request not always has associated data. Modelling this with null-values is a bad decision, because you have to check for this every time you want to use your data. At some point you want to handle Request without data in a different way then Request with data.
Maybe you should make your Request to an interface containing Methods like getName() and getCode() and create two concrete classes RequestWithData<T> and RequestWithoutData implementing this interface. Then you can check on creation of an RequestWithData<T>-instance, if a non-null data is provided. Furthermore, you can express in your method signature that you require a Request with data or without data. This leads to a more clean design and avoids your problem.
Use the new 'Optional' type in Java 8. It was made specifically for cases like these. If you cannot, for whatever reason, use Java 8 yet, the Google Guava library also implements that type. Check this example : https://gist.github.com/9833966

Controlling when object is created

Suppose i need to create an object as follows and set some values
FileMetaData fileMeta = fileContainer.getMetaData();
fileMeta.setFileName("file name");
fileMeta.setServer("my box");
fileMeta.setDirectory("/path/to/dir");
fileMeta.setFileType(FileType.PROPERTIES);
I later intend to use this object reference to do something useful.
I'd like to recognize the fact that it is possible for the user of the system to not set some fields, for instance, one may forget to
fileMeta.setDateModified(12345);
Is it somehow possible to guarantee that all (or some specific) fields are set before making the object available?
There is nothing in the language to enforce this (except for having a lone visible constructor that takes all the required parameters), but you can do it idiomatically, with a variation on the builder pattern and some method chaining:
FileMetaData fileMeta = new FileMetaDataBuilder(fileContainer.getMetaData())
.setFileName("file name")
.setServer("my box")
.setDirectory("/path/to/dir")
.setFileType(FileType.PROPERTIES)
.build();
The build() method can ensure that all the required fields are set before calling the appropriate constructor of FileMetaData with all the required parameters.
Use the builder pattern and pass the reference to the builder around. When you're done adding extras on top, call .build and capture the returned instance of FileMetaData.
You could constrain it by not allowing the build to succeed until all of the pre-requisites are set.
Basically I can classify the following 3 ways.
First is based on the class itself. You can add method isReady() to your class. This method will perform all checks and return true or false.
Other way is to use Factory or Builder pattern and probably objects repository. Both factory and builder guarantee to create object in ready state. Repository can be used to "publish" ready objects there, so other code requests objects and receives them in ready state only.
Other approach is to use Wrapper (Decorator) pattern.
interface Foo {
public void foo(); //business method
}
class FooImpl implements Foo {
public void foo(){} // does the work
}
class FooDecorator implmeents Foo {
Foo foo;
public void foo(){
if (isInitialized()) {
foo.foo();
}
throw IllegalStateException("Not initialized");
}
}
This solutions may be implemented using dynamic proxy or using AOP framework as well.

how to read object attribute dynamically in java?

Is there any way to read and print the object attribute dynamically(Java) ? for example if I have following object
public class A{
int age ;
String name;
float income;
}
public class B{
int age;
String name;
}
public class mainA{
A obj1 = new A();
method(A);
method(B);
}
the output should be like
While running method(A):
Attribute of Object are age,name,income;
While executing method(B):
Attribute of Objects are age,name;
My question is I can pass various object in method(), is there any way I can access the attribute of the differnt object in general.
You want to use The Reflection API. Specifically, take a look at discovering class members.
You could do something like the following:
public void showFields(Object o) {
Class<?> clazz = o.getClass();
for(Field field : clazz.getDeclaredFields()) {
//you can also use .toGenericString() instead of .getName(). This will
//give you the type information as well.
System.out.println(field.getName());
}
}
I just wanted to add a cautionary note that you normally don't need to do anything like this and for most things you probably shouldn't. Reflection can make the code hard to maintain and read. Of course there are specific cases when you would want to use Reflection, but those relatively rare.
Using org.apache.commons.beanutils.PropertyUtils we can do this. If the proper getters and setters are defined for the bean we can also dynamically set the value:
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;
public class PropertyDescriptorTest {
public static void main(String[] args) {
// Declaring and setting values on the object
AnyObject anObject = new AnyObject();
anObject.setIntProperty(1);
anObject.setLongProperty(234L);
anObject.setStrProperty("string value");
// Getting the PropertyDescriptors for the object
PropertyDescriptor[] objDescriptors = PropertyUtils.getPropertyDescriptors(anObject);
// Iterating through each of the PropertyDescriptors
for (PropertyDescriptor objDescriptor : objDescriptors) {
try {
String propertyName = objDescriptor.getName();
Object propType = PropertyUtils.getPropertyType(anObject, propertyName);
Object propValue = PropertyUtils.getProperty(anObject, propertyName);
// Printing the details
System.out.println("Property="+propertyName+", Type="+propType+", Value="+propValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
To set the value of a particular property:
// Here we have to make sure the value is
// of the same type as propertyName
PropertyUtils.setProperty(anObject, propertyName, value);
Output will be:
Property=class, Type=class java.lang.Class, Value=class genericTester.AnyObject
Property=intProperty, Type=int, Value=1
Property=longProperty, Type=class java.lang.Long, Value=234
Property=strProperty, Type=class java.lang.String, Value=string value
You can use reflection to get every field from your object (if security configuration allows you).
If you need it not for the sake of self-education, then it may be worth using ReflectionUtils from Apache Commons.
You can use reflection, but the API is not very nice to use. But what you are trying to do is not at all object-oriented. The A and B should have method "print yourself" which would output their values (you should specify the method in superclass/interface to call the method using polymorphism).
I think I would consider a different approach.
If you really want to treat these like data is there any reason they couldn't be hashtables (Do they have associated code)?
Reflection will do it but it's a last resort--you should always seriously consider different approaches before dropping to reflection.
Cases where you must access variables like that exist--like database mapping (Hibernate) and injection (Spring). You might want to consider if a packaged solution like that fits your need so that future programmers can understand what you did without learning everything about your specific solution.
Also, Spring injection can do things that might fit your needs.
Also also if you are going to use reflection, seriously consider annotations so that you aren't tying your functionality to what should be simple arbitrary attribute names.

Categories

Resources