Example I have data layer after
public class DemoData implements Cloneable {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); //To change body of generated methods, choose Tools | Templates.
}
}
I want to assign data values (DemoData) to a duplicate data (DemoData clone) layer as follows
public static void main(String[] args) {
DemoData demoData = new DemoData();
demoData.setName("Class Sources");
testReflectionDemo(demoData);
}
private static DemoData testReflectionDemo(DemoData demoData) {
try {
DemoData clone = (DemoData) demoData.clone();
clone.setName(demoData.getName());
clone.setValue(demoData.getValue());
return clone;
} catch (CloneNotSupportedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
I want to convert the method testReflectionDemo(DemoData demoData) to method testReflectionDemo(T t) reflection as shown below.I do not know how to continue, please help me
public <T> T testReflectionDemo(T t){
Class<?> aClass = t.getClass();
for (Method method : aClass.getMethods()) {
}
return null;
}
Thank you all for the help for my question,I've removed the clone method, I just applied reflection.Hi #dabaicai.Your code helped me with the idea,I thought passing the value to the private field would be easier a little.
public static <T> T clazzClone(T t) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
Class<?> clazzRoot = t.getClass();
Object newInstance = clazzRoot.newInstance();
Field[] fieldsClone = newInstance.getClass().getDeclaredFields();
for (Field fieldClone : fieldsClone) {
fieldClone.setAccessible(true);
fieldClone.set(newInstance, getContent(t, fieldClone.getName()));
}
return (T) newInstance;
}
private static String getContent(Object aClass, String name) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field declaredField = aClass.getClass().getDeclaredField(name);
declaredField.setAccessible(true);
return (String) declaredField.get(aClass);
}
My program means when I need to edit user input data to output the results I want,with a common filter function
fieldClone.set(newInstance,methodYourEdit(getContent(t, fieldClone.getName())));
If the argument of testReflectionDemo is a javabean,it means that the class of argument have several a pair method of setXXX and 'getXXX,and thegetXXXdon't have argument,thesetXXX` just have one argument.If is this,the following code can copy the property from old object to new object.
Class<?> aClass = t.getClass();
Object result = aClass.newInstance();
Map<String,MethodHolder> map=new HashMap<>();
for (Method method : aClass.getMethods()) {
if(method.getName().startsWith("get") && method.getParameterTypes().length==0){
String property=method.getName().substring(3);
MethodHolder hodler = map.get(property);
if(hodler ==null){
map.put(property, new MethodHolder(property, method, null));
continue;
}
hodler.getMethod=method;
}else if (method.getName().startsWith("set") && method.getParameterTypes().length==1) {
String property=method.getName().substring(3);
MethodHolder holder = map.get(property);
if(holder ==null){
map.put(property, new MethodHolder(property, null, method));
continue;
}
holder.setMethod=method;
}
}
List<MethodHolder> collect = map.values().stream().filter(item -> item.setMethod != null && item.getMethod != null).collect(Collectors.toList());
for (MethodHolder holder : collect) {
Object property = holder.getMethod.invoke(t);
holder.setMethod.invoke(result,property);
}
return (T)result;
The MethodHolder just have some field:
public static class MethodHolder{
private String property;
private Method getMethod;
private Method setMethod;
public MethodHolder() {
}
public MethodHolder(String property, Method getMethod, Method setMethod) {
this.property = property;
this.getMethod = getMethod;
this.setMethod = setMethod;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MethodHolder)) return false;
MethodHolder that = (MethodHolder) o;
return Objects.equals(property, that.property);
}
#Override
public int hashCode() {
return Objects.hash(property);
}
}
Pay attention of that the following code just make shallow copy.
Related
I have hazelcast client that is putting generic message class into a iQueue and hazelcast member consume this generic message via Listener do the logic and remove the object from the queue. But it is not removing all the objects. On mancenter i can see that there are still items into the queue (not all for example from 100 objects in queue it is removing around 80 from them) and i don`t know why it is not removing some of the objects.
Currently in mancenter it is showing 12 items into the queue (from arround 100 requests) but it shouldn't have any.Still the code is working and returning results. The only problem is that i can see in mancenter that this items are getting more and more into the queue until i stop the hazelcast server.
My generic message class:
public class GenericMessage<T> implements Message<T>, Serializable {
private static final long serialVersionUID = -1927585972068115172L;
private final T payload;
private MessageHeaders headers;
public GenericMessage(T payload) {
Assert.notNull(payload, "payload must not be null");
HashMap<Object, Object> headers = new HashMap<>();
this.headers = new MessageHeaders(headers);
this.payload = payload;
}
#Override
public MessageHeaders getHeaders() {
return this.headers;
}
#Override
public T getPayload() {
return this.payload;
}
#Override
public String toString() {
return "[Payload=" + this.payload + "][Headers=" + this.headers + "]";
}
#Override
public int hashCode() {
return this.headers.hashCode() * 23 + ObjectUtils.nullSafeHashCode(this.payload);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof GenericMessage<?>) {
GenericMessage<?> other = (GenericMessage<?>) obj;
if (this.headers.getKey() != null && other.headers.getKey() != null) {
return this.headers.getKey().equals(other.headers.getKey());
} else {
return false;
}
}
return false;
}
}
MessageHeaders class:
public class MessageHeaders implements Map<Object, Object>, Serializable {
private static final long serialVersionUID = 4469807275189880042L;
protected Map<Object, Object> headers;
public static final String KEY = "key";
public MessageHeaders(Map<Object, Object> headers) {
this.headers = (headers != null) ? headers : new HashMap<>();
}
#SuppressWarnings("unchecked")
public <T> T get(Object key, Class<T> type) {
Object value = this.headers.get(key);
if (value == null) {
return null;
}
if (!type.isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Incorrect type specified for header '"
+ key
+ "'. Expected ["
+ type
+ "] but actual type is ["
+ value.getClass()
+ "]");
}
return (T) value;
}
#Override
public int hashCode() {
return this.headers.hashCode();
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof MessageHeaders) {
MessageHeaders other = (MessageHeaders) obj;
return this.headers.equals(other.headers);
}
return false;
}
#Override
public boolean containsKey(Object key) {
return this.headers.containsKey(key);
}
#Override
public boolean containsValue(Object value) {
return this.headers.containsValue(value);
}
#Override
public Set<Map.Entry<Object, Object>> entrySet() {
return Collections.unmodifiableSet(this.headers.entrySet());
}
#Override
public Object get(Object key) {
return this.headers.get(key);
}
#Override
public boolean isEmpty() {
return this.headers.isEmpty();
}
#Override
public Set<Object> keySet() {
return Collections.unmodifiableSet(this.headers.keySet());
}
#Override
public int size() {
return this.headers.size();
}
#Override
public Collection<Object> values() {
return Collections.unmodifiableCollection(this.headers.values());
}
#Override
public Object put(Object key, Object value) {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
#Override
public void putAll(Map<? extends Object, ? extends Object> t) {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
#Override
public Object remove(Object key) {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
#Override
public void clear() {
throw new UnsupportedOperationException("MessageHeaders is immutable.");
}
private void writeObject(ObjectOutputStream out) throws IOException {
List<String> keysToRemove = new ArrayList<>();
for (Map.Entry<Object, Object> entry : this.headers.entrySet()) {
if (!(entry.getValue() instanceof Serializable)) {
keysToRemove.add(String.valueOf(entry.getKey()));
}
}
for (String key : keysToRemove) {
// if (logger.isInfoEnabled()) {
// logger.info("removing non-serializable header: " +
// key);
// }
this.headers.remove(key);
}
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
}
public String getKey() {
return this.get(KEY, String.class);
}
public void setKey(String key) {
this.headers.put(KEY, key);
}
}
Putting into queue implementation:
User user = new User();
GenericMessage<User> message = new GenericMessage<User>(user);
String key="123";
message.getHeaders().setKey(key);
IQueue<Object> queue = hazelcastInstance.getQueue("user_queue");
queue.add(message);
Hazelcast listener configuration:
IQueue<Object> userQueue = hazelcastInstance.getQueue("user_queue");
UserListener userListener = context.getBean(UserListener.class);
userQueue.addItemListener(userListener, true);
Listener:
public class UserListener implements ItemListener<Object> {
#Autowired
private UserService service;
#Override
public void itemAdded(ItemEvent<Object> arg0) {
service.process(arg0);
}
}
Service:
public class UserService {
#Async("userTaskExecutor")
public void process(ItemEvent<Object> item) {
GenericMessage<User> message = (GenericMessage<User>) item.getItem();
hazelcastInstance.getQueue("user_queue").remove(message);
}
With a lot of testing and debugging i found the problem.
It turns out that the documentation of the remove(object) method is misleading. In the documentation is says that this method rely on .equals() class method but it turns out that hazelcast compares the serialized object against each serialized object. So i implement a custom compare:
GenericMessage<?> incomeMessage = (GenericMessage<?>) object;
boolean removed = hazelcastInstance.getQueue(queueId).remove(object);
if (!removed) {
Iterator<Object> iterator = hazelcastInstance.getQueue(queueId).iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
GenericMessage<?> message = (GenericMessage<?>) next;
if (incomeMessage.getHeaders().getKey()
.equals(message.getHeaders().getKey())) {
object = next;
removed = hazelcastInstance.getQueue(queueId).remove(object);
break;
}
}
}
I have created a method in which i have multiple if conditions. Now i want to refactor these if conditions. What would be the best design pattern/strategy to overcome multiple if conditions?
if
(
poConfiguration.strSampleLoaderPluginClass != null
&& poConfiguration.strSampleLoaderPluginClass.equals("") == false
)
{
setSampleLoaderPluginClass(poConfiguration.strSampleLoaderPluginClass);
}
if
(
poConfiguration.strPreprocessingPluginClass != null
&& poConfiguration.strPreprocessingPluginClass.equals("") == false
)
{
setPreprocessingPluginClass(poConfiguration.strPreprocessingPluginClass);
}
if
(
poConfiguration.strFeatureExtractionPluginClass != null
&& poConfiguration.strFeatureExtractionPluginClass.equals("") == false
)
{
setFeatureExtractionPluginClass(poConfiguration.strFeatureExtractionPluginClass);
}
if
(
poConfiguration.strClassificationPluginClass != null
&& poConfiguration.strClassificationPluginClass.equals("") == false
)
{
setClassificationPluginClass(poConfiguration.strClassificationPluginClass);
}
Please share your thoughts with implementations, if possible. Thanks in advance
My first idea would be the polymorphism (Click here for more info), it depends from the concrete situation:
interface MyInterface {
public boolean checkCondition(PoConfiguration poConfiguration);
public void process(PoConfiguration poConfiguration);
}
public class SampleLoader implements MyInterface {
public boolean checkCondition(PoConfiguration poConfiguration) {
return poConfiguration.strSampleLoaderPluginClass != null
&& !poConfiguration.strSampleLoaderPluginClass.isEmpty();
}
public void process(PoConfiguration poConfiguration) {
setSampleLoaderPluginClass(poConfiguration.strSampleLoaderPluginClass);
}
}
public class ClientAPI {
public void caller() {
for (MyInterface current : this.myInterfaces) {
if (current.checkCondition(current)) {
current.process();
}
}
}
You might try something like the following:
Create a Configuration class that contains ConfigurationItems
Each ConfigurationItem would have a name, value and a default value
As an improvement, you may want to create static values for the configuration items instead of using Strings.
TestConfig main Class
package com.example.config;
public class TestConfig {
static TestConfig me;
static String[][] confSettings = {{"sampleLoader","loaderDefault"}
,{"preProcessing","preProcessingDefualt"}
,{"featureExtraction","featureExtractionDefault"}
,{"classification","classificationDefault"}
};
// Object fields
Configuration configuration;
public static void main(String[] args) {
// TODO Auto-generated method stub
me = new TestConfig();
me.doWork();
}
private void doWork() {
configuration = new Configuration();
for (int i=0; i < confSettings.length; i++) {
configuration.addConfigurationItem(confSettings[i][0], confSettings[i][1], null);
}
configuration.setConfigurationItemDefault("classification", "newValue");
System.out.println("sampleLoader = " + configuration.getConfigurationItemValue("sampleLoader"));
System.out.println("classification = " + configuration.getConfigurationItemValue("classification"));
}
}
Configuration Class
package com.example.config;
import java.util.ArrayList;
import java.util.HashMap;
public class Configuration {
// Class fields
// Object fields
HashMap<String,Integer> itemNames;
ArrayList<ConfigurationItem> items;
public Configuration() {
items = new ArrayList<ConfigurationItem>();
itemNames = new HashMap<String,Integer>();
}
public Configuration addConfigurationItem(String name, String defaultValue, String value) {
if (itemNames.containsKey(name)) {
// handle duplicate configuration item
} else {
items.add(new ConfigurationItem(name, defaultValue, value));
Integer loc = new Integer(items.size()-1);
itemNames.put(name, loc);
}
return this;
}
public void setConfigurationItemDefault(String name, String defaultValue) {
int loc = getConfigurationItemIndex(name);
if (loc > -1) {
items.get(loc).setDefaultValue(defaultValue);
}
}
public String getConfigurationItemValue(String name) {
int loc = getConfigurationItemIndex(name);
if (loc > -1) {
return items.get(loc).getValue();
} else {
// handle unknown parameter
return null;
}
}
private int getConfigurationItemIndex(String name) {
if (itemNames.containsKey(name)) {
return itemNames.get(name);
} else {
// handle unknown parameter
return -1;
}
}
}
ConfigurationItem Class
package com.example.config;
public class ConfigurationItem {
// Object fields
String name;
String value;
String defaultValue;
public ConfigurationItem(){};
public ConfigurationItem(String name, String defaultValue, String value) {
this.setName(name).setDefaultValue(defaultValue).setValue(value);
}
public ConfigurationItem setName(String name) {
this.name = name;
return this;
}
public ConfigurationItem setValue(String value) {
this.value = value;
return this;
}
public ConfigurationItem setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public String getValue() {
if (value == null || value.length() == 0) {
return defaultValue;
} else {
return value;
}
}
}
public class ObjectToProxy
{
List<ObjectToProxy> potentiallyCircularReference;
}
public class SubClass
{
private ObjectToProxy aField;
Set<ObjectToProxy> aSetOfObjectsToProxy;
}
public class CrazyObject
{
Map<Integer, ObjectToProxy> proxiedObjects;
List<SubClass> manySubClasses;
}
public class ComplexObject
{
List<CrazyObject> crazyObjects;
private final ObjectToProxy storedAsAField;
}
I have a complex object graph. Lets say it looks a little like the one above (even though it is much deeper in the real system). I would like, after being given ComplexObject, to be able to traverse the object graph and replace all ObjectToProxys with a proxying object.
Is this doable?
The reason for this is that we have some pretty big nasty objects which we partially load on the servers side (legacy, you're my friend!). We have a semi-working solution that uses proxying on the client side to go through and loads the full object when needed.
edit I would like to replace every instance of ObjectProxy connected to a ComplexObject.
public static class ProxyObject extends ObjectToProxy
{
private final ObjectToProxy objectToProxy;
public ProxyObject(ObjectToProxy objectToProxy)
{
this.objectToProxy = objectToProxy;
}
#Override
public String toString()
{
return "ProxyObject";
}
}
public static class ObjectToProxy
{
List<ObjectToProxy> potentiallyCircularReference;
public ObjectToProxy()
{
potentiallyCircularReference = new ArrayList<>();
potentiallyCircularReference.add(this);
}
#Override
public String toString()
{
return "ObjectToProxy";
}
}
public static class SubClass
{
ObjectToProxy aField;
Set<ObjectToProxy> aSetOfObjectsToProxy;
}
public static class CrazyObject
{
Map<Integer, ObjectToProxy> proxiedObjects;
List<SubClass> manySubClasses;
public CrazyObject()
{
proxiedObjects = new HashMap<>();
proxiedObjects.put(1, new ObjectToProxy());
}
}
public static class ComplexObject
{
List<CrazyObject> crazyObjects;
final ObjectToProxy storedAsAField;
public ComplexObject()
{
this.storedAsAField = new ObjectToProxy();
crazyObjects = new ArrayList<>();
crazyObjects.add(new CrazyObject());
}
#Override
public String toString()
{
return "myField: " + storedAsAField.toString();
}
}
public static void main(String[] args) throws Exception
{
ComplexObject obj = new ComplexObject();
Set<Object> visitedObjects = Sets.newIdentityHashSet();
Queue<Object> objectsToVisit = new LinkedList<>();
visitedObjects.add(obj);
objectsToVisit.add(obj);
while (!objectsToVisit.isEmpty())
{
handleFields(objectsToVisit.poll(), visitedObjects, objectsToVisit);
}
System.out.println(obj.toString());
}
private static void handleFields(Object obj, Set<Object> visitedObjects, Queue<Object> objectsToVisit) throws Exception
{
List<Field> fields = getAllFields(obj);
for (Field field : fields)
{
field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue != null && !visitedObjects.contains(fieldValue))
{
if (fieldValue instanceof Object[])
{
visitedObjects.add(fieldValue);
Object[] array = (Object[])fieldValue;
for (Object arrayObj : array)
{
if (arrayObj != null && !objectsToVisit.contains(arrayObj))
{
visitedObjects.add(arrayObj);
if (!DontLookAt.contains(arrayObj.getClass()))
objectsToVisit.add(arrayObj);
}
}
}
else
{
if (!DontLookAt.contains(fieldValue.getClass()))
objectsToVisit.add(fieldValue);
}
if (fieldValue.getClass().equals(ObjectToProxy.class))
{
field.set(obj, new ProxyObject((ObjectToProxy)fieldValue));
}
else if (fieldValue instanceof ObjectToProxy[])
{
ObjectToProxy[] array = (ObjectToProxy[])fieldValue;
for (int i = 0; i < array.length; i++)
{
if (array[i] != null)
array[i] = new ProxyObject(array[i]);
}
}
}
}
}
private static final Set<Class> DontLookAt = getDontLookAtSet();
private static Set<Class> getDontLookAtSet()
{
Set<Class> set = new HashSet<>();
set.add(Long.class);
set.add(Boolean.class);
set.add(Integer.class);
set.add(String.class);
set.add(Byte.class);
set.add(Double.class);
set.add(Float.class);
set.add(Class.class);
return set;
}
private static List<Field> getAllFields(Object obj) throws Exception
{
List<Field> output = new ArrayList<>();
Class klazz = obj.getClass();
while (!klazz.equals(Object.class))
{
Field[] fields = klazz.getDeclaredFields();
output.addAll(Arrays.asList(fields));
klazz = klazz.getSuperclass();
}
return output;
}
For anyone wondering, The above simulates and does what I'm after. I'm sure it isn't perfect, but it is good enough for my purposes.
I'd like to write a method, that does return something of a PrimitiveType like float, integer, boolean and also String if possible. I'd like to use generics for it but i stuck and dont find a solution for it. I do need it for a Configparser. Ill use it to get different values from the Config.
Current it des look like this and i know that the switch does not work like this but you get an idea of what id like to do:
public class ConfigurationManager extends XmlReader {
private final static String FILE_PATH = "config/config.cfg";
private static Element xml;
public ConfigurationManager() throws IOException {
FileHandle handle = Gdx.files.internal(FILE_PATH);
this.xml = this.parse(handle);
}
public Resolution getResolution() {
Resolution r = new Resolution();
r.height = xml.getFloat("height");
r.width = xml.getFloat("width");
return r;
}
public static <T> T getConfig(Class<T> type, String name) {
if (type.equals(Integer.class)) {
return type.cast(xml.getInt(name));
} else if (type.equals(Float.class)) {
return type.cast(xml.getFloat(name));
} else if (type.equals(Boolean.class)) {
return type.cast(xml.getBoolean(name));
} else if (type.equals(String.class)) {
return type.cast(xml.get(name));
}
throw new AssertionError("Invalid type");
}
}
Thanks alot
Well, I don't think you can do it with primitive types directly, but how about something like this:
public static <T> T getConfig(Class<T> type, String name) {
if(type.equals(Integer.class)){
return type.cast(xml.getInteger(name));
} else if(type.equals(Float.class)){
return type.cast(xml.getFloat(name));
} else if(type.equals(Double.class)) {
return type.cast(xml.getDouble(name));
} else if(type.equals(String.class)) {
return type.cast(xml.getString(name));
}
throw new AssertionError("Invalid type");
}
You could use an Enum to avoid the branching logic and the explicit casting.
public enum TypeSelector {
INTEGER() {
#Override
public Integer getValue(Elements xml, String name) {
return xml.getInteger(name);
}
},
DOUBLE() {
#Override
public Double getValue(Elements xml, String name) {
return xml.getDouble(name);
}
};
private static final Map<Class<?>, TypeSelector> SELECTORS = new HashMap<Class<?>, TypeSelector>() {
{
put(Integer.class, INTEGER);
put(Double.class, DOUBLE);
}
};
public static <T> TypeSelector getSelectorForType(Class<T> c) {
TypeSelector selector = SELECTORS.get(c);
if (selector == null) {
throw new AssertionError("Invalid type");
}
return selector;
}
public abstract <T> T getValue(Elements xml, String name);
}
I've done some fancy wrapping to avoid unchecked warnings in the past, but after 90 mins of poring over http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html, I can't write the findMatch method below and make it work without #SuppressWarnings("unchecked"). The parameterized class isn't known at compile time.
public interface Matchable<T>
{
public boolean matches(T toMatch);
}
public class PlaceForMatching
{
public static Object findMatch(Object toMatch, Object[] toSearch)
{
if(!(toMatch instanceof Matchable)) return null;
Matchable matchObj = (Matchable)toMatch;
Class<?> matchClass = matchObj.getClass();
for(Object obj : toSearch)
{
/**
* Check here verifies that the search list object we're about
* to check is the same class as the toMatch object.
* This means Matchable will work without a ClassCastException.
**/
if(matchClass.isInstance(obj) && matchObj.matches(obj))
return obj;
}
//Didn't find it
return null;
}
}
Note the code works because in every case Matchable is implemented by T.
Apple implements Matchable<Apple>
Orange implements Matchable<Orange>
EDIT: Add some test code
public static void main(String[] args)
{
Object[] randomList = createAppleArray();
Object apple = new Apple("Red");
Object match = findMatch(apple, randomList);
}
private static Object[] createAppleArray()
{
return new Object[] { new Apple("Pink"), new Apple("Red"), new Apple("Green") };
}
public class Apple implements Matchable<Apple>
{
String color;
public Apple(String color)
{
this.color = color;
}
public boolean matches(Apple apple)
{
return color.equals(apple.color);
}
}
public static <T extends Matchable<T>> T findMatch(T toMatch, T[] toSearch) {
if (toMatch == null)
return null;
Matchable<T> matchObj = toMatch;
Class<?> matchClass = matchObj.getClass();
for (T obj : toSearch) {
if (matchClass.isInstance(obj) && matchObj.matches(obj))
return obj;
}
return null;
}