The problem is the following. Given a class GenericConfig which encapsulates a Map<String, Object> to contain several configurations, a class SpecificConfig is desired to have getters to retrieve specific map values.
For example, I want to avoid testing that GenericConfig.getProperties().get(KEY_OF_PROPERTY); is null and getting the value, with the burden of memorizing the key value in the calling method. I want to create a SpecificConfig that is created only if the key is present and that has a getProperty() method.
Example of what I want to avoid:
private final static String KEY_OF_PROPERTY = "key.for.my.value";
public void process(List<GenericConfig> configs) {
for(GenericConfig config: configs) {
String value = config.getProperties().get(KEY_OF_PROPERTY);
if (value != null) {
// do something
}
}
}
This is my attempt:
public final class SpecificConfig extends GenericConfig {
public SpecificConfig(GenericConfig from) {
if(from.getProperties().get(KEY_OF_PROPERTY) != null) {
this.properties = from.getProperties();
} else {
throw new ThisIsNotTheConfigIWant();
}
}
public String getProperty() {
return (String) this.properties.get(KEY_OF_PROPERTY);
}
}
So I can do the following:
public void process(List<GenericConfig> configs) {
for(GenericConfig config: configs) {
try {
SpecificConfig c = new SpecificConfig(config);
// now i can be sure that c is of the required type
// do stuff related to that type
} catch (ThisIsNotTheConfigIWant) { /* ignore this config */ }
}
}
Is throwing a checked exception in the constructor a bad thing in OOP? Does a pattern to solve this problem exist? Is it viable to instantiate null in the constructor instead of throwing an exception.
When calling the constructor it must return an instance of the class, never null. But if you want it to be possible to be null, use a static factory method instead:
public SpecificConfig maybeCreateFrom(GenericConfig c) {
if (<matches>) {
return SpecificConfig(c);
} else {
return null;
}
}
Then on the for-loop you can check for not-null. I think that is generally better than using clunky exceptions for control-flow handling. Though I suspect this is still not the best architecture for you.
Does the class GenericConfig holds a single config or a Map of configs? I would consider just creating methods to fetch configs with the existing keys + doing any null checks. Then you can just call getConfigX() or something.
Related
I am working on a Spring Boot application and I have the following doubt.
I have this service method (that works fine) that insert an object into the DB calling the repository:
#Override
#Transactional
public CoinDTO createCoin(CoinDTO coin) throws DuplicateException {
Coin checkCoinExists = coinRepository.findByCode(coin.getCode());
if (checkCoinExists != null) {
String MsgErr = String.format("Coin %s already registered in the system !!! "
+ "Impossible to use POST", coin.getCode());
log.warning(MsgErr);
throw new DuplicateException(MsgErr);
}
Coin result = coinRepository.save(conversionService.convert(coin,Coin.class));
return conversionService.convert(result,CoinDTO.class);
}
As you can see the save() methjod return the inserted Coin object (that is an Hibernate entity class mapping my table). The service method than convert this Coin object into the CoinDTO object in order to return the DTO object instead the entity instance. It works fine and it is the expected behavior.
Now I created this second service method that simply retrieve the list of all the Coin objects and must return the list of the related CoinDTO objects:
#Override
public List<CoinDTO> getCoinList() {
List<Coin> coinsList = this.coinRepository.findAll();
return null;
}
and here I have the following doubt: I think that I can implement thid ENTITY to DTO conversion behavior iterating on the coinsList element, converting each element of the list one by one and then adding it to a new List list. It should work
Exist some more modern and smarter way to do it? Maybe using lambda function? Can you help me to implement this behavior in a modern and a smart way?
You may create an generic abstract class like this:
public abstract class AbstractConverter<T, DTO> {
public abstract T fromDto(DTO dto);
public abstract DTO toDTO(T t);
public List<T> fromDTOs(List<DTO> dtos) {
if (dtos == null || dtos.isEmpty()) {
return null;
} else {
return dtos.stream().map(this::fromDTO).collect(Collectors.toList());
}
}
public List<DTO> toDTOs(List<T> ts) {
if (ts == null || ts.isEmpty()) {
return null;
} else {
return ts.stream().map(this::toDTO).collect(Collectors.toList());
}
}
}
Then create another class that implements the aforecreated abstract class by assigning your desired values like this:
#Component(value = "coinConverter")
public class CoinConverter extends AbstractConverter<Coin, CoinDTO> {
#Override
public Coin fromDTO(CoinDTO dto) {
if (dto == null) {
return null;
} else {
Coin coin = new Coin();
// Assign all values you wanted to consume
// of the following form
// coin.setYourAttribite(dto.getYourAttribute())
return coin;
}
}
#Override
public CoinDTO toDTO(Coin coin) {
if (t == null) {
return null;
} else {
CoinDTO coinDTO = new CoinDTO();
// Assign all values you wanted to expose
// of the following form
// coinDTO.setYourAttribite(coin.getYourAttribute())
return coinDTO;
}
}
}
In controller layer you may change your existing code by this one:
#Autowired
#Qualifier("coinConverter")
AbstractConverter<Coin, CoinDTO> abstractConverter;
#Override
public List<CoinDTO> getCoinList() {
List<Coin> coinsList = this.coinRepository.findAll();
return abstractConverter.toDTOs(cointList);
}
This way your code is flexible to add more converters without changing the existing ones.
As far as I understand, you are looking for a way that makes the conversion process shorter and more convenient. if so use ModelMapper class in this case, read this http://modelmapper.org/ documentation, ModelMapper uses TypeTokens to allow mapping of generic parameterized types.
Not sure if I understood your question, but is the following what you are looking for:
#Override
public List<CoinDTO> getCoinList() {
return this.coinRepository.findAll().stream()
.map(coin -> conversionService.convert(coin, CoinDTO.class))
.collect(Collectors.toList());
}
Wicket 6 has a default compound request mapper: SystemMapper. It contains BookmarkableMapper. I need to override it, that is, use my own FancyBookmarkableMapper instead.
What I tried:
Copy SystemMapper class as a whole and change the following line
add(new BookmarkableMapper());
to
add(new FancyBookmarkableMapper());
But this way is very ugly and fragile upgrade-wise (although it seems to work). I mention it here just for the sake of completeness.
Using the fact that SystemMapper is ICompoundMapper, replace the mapper using add(), remove() and iterator() methods:
private SystemMapper customizeSystemMapper() {
final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper();
IRequestMapper originalBookmarkableMapper = null;
boolean afterBookmarkable = false;
List<IRequestMapper> mappersAfterBookmarkable = new ArrayList<>();
for (IRequestMapper mapper : rootRequestMapper) {
if (mapper.getClass() == BookmarkableMapper.class) {
if (originalBookmarkableMapper != null) {
throw new IllegalStateException("There are two BookmarkableMapper instances in the initial mappers list");
}
originalBookmarkableMapper = mapper;
afterBookmarkable = true;
} else {
if (afterBookmarkable) {
mappersAfterBookmarkable.add(mapper);
}
}
}
if (originalBookmarkableMapper == null) {
throw new IllegalStateException("There is no BookmarkableMapper in the initial mappers list");
}
for (IRequestMapper mapperToRemove : mappersAfterBookmarkable) {
rootRequestMapper.remove(mapperToRemove);
}
rootRequestMapper.remove(originalBookmarkableMapper);
rootRequestMapper.add(new FancyBookmarkableMapper());
for (IRequestMapper mapperToAdd : mappersAfterBookmarkable) {
rootRequestMapper.add(mapperToAdd);
}
return rootRequestMapper;
}
Not very nice too, although it works as well.
Build an implementation of ICompoundMapper and decorate SystemMapper instance with it. The only way to substitute the built-in mapper is to try to play with iterator() method:
#Override
public Iterator<IRequestMapper> iterator() {
return new Iterator<IRequestMapper>() {
private Iterator<IRequestMapper> originalIterator = delegate.iterator();
#Override
public boolean hasNext() {
return originalIterator.hasNext();
}
#Override
public IRequestMapper next() {
IRequestMapper nextMapper = originalIterator.next();
if (nextMapper != null && nextMapper.getClass() == BookmarkableMapper.class) {
nextMapper = bookmarkableMapperReplacement;
}
return nextMapper;
}
#Override
public void remove() {
originalIterator.remove();
}
};
}
However, this does NOT work, as SystemMapper#mapRequest() (actually defined in CompoundRequestMapper) uses mappers field directly and not via iterator() method.
The easiest way:
private SystemMapper customizeSystemMapper2() {
final SystemMapper rootRequestMapper = (SystemMapper) getRootRequestMapper();
rootRequestMapper.add(new FancyBookmarkableMapper());
return rootRequestMapper;
}
Here we add our mapper to the beginning of the list. It extends BookmarkableMapper and inherits its getCompatibilityScore(), so it has the same score as BookmarkableMapper has, and it is earlier in the list, so it takes precedence.
This item 4 actually works. The only thing that makes me ask this question is that actually, both mappers are in the internal list of SystemMapper for this approach. Is it guaranteed that my mapper (that was added later and has the same score) will take precedence (including future Wicket versions)?
The easiest (and official) way is to use WebApplication#mount(new FancyBookmarkableMapper () in YourApplication#init() method.
I'll check tomorrow your concern in 3)! Update: improved it with https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=0eb63480;hp=5821157738ac43a09232a2aeb0fa2ff808340f4d
Please let us know if you see more improvements! Thank you!
Is it possible to dynamically call a method on a class from java?
E.g, lets say I have the reference to a class, e.g either the string: 'com.foo.Bar', or com.foo.Bar.class, or anything else which is needed..). And I have an array / list of strings, e.g [First, Last, Email].
I want to simply loop through this array, and call the method 'validate' + element on the class that I have a reference to. E.g:
MyInterface item = //instantiate the com.foo.Bar class here somehow, I'm not sure how.
item.validateFirst();
item.validateLast();
item.validateEmail();
I want the above lines of code to happen dynamically, so I can change the reference to a different class, and the names in my string list can change, but it will still call the validate + name method on whichever class it has the reference to.
Is that possible?
The simplest approach would be to use reflection
Given...
package com.foo;
public class Bar {
public void validateFirst() {
System.out.println("validateFirst");
}
public void validateLast() {
System.out.println("validateLast");
}
public void validateEmail() {
System.out.println("validateEmail");
}
}
You could use something like...
String methodNames[] = new String[]{"First", "Last", "Email"};
String className = "com.foo.Bar";
try {
Class classRef = Class.forName(className);
Object instance = classRef.newInstance();
for (String methodName : methodNames) {
try {
Method method = classRef.getDeclaredMethod("validate" + methodName);
method.invoke(instance);
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
ex.printStackTrace();
}
To look up the methods and execute them.
You will need to decide the best way to handle errors and what they mean to you, but it wouldn't be a difficult them to expand the idea to a reusable method...
Updated with idea of concept discussed in comments
Given....
public interface Validator {
public boolean isValid(Properties formProperties);
}
We can create one or more...
public class UserRegistrationValidator implements Validator {
public boolean isValid(Properties formProperties) {
boolean isValid = false;
// Required fields...
if (formProperties.containsKey("firstName") && formProperties.containsKey("lastName") && formProperties.containsKey("email")) {
// Further processing, valid each required field...
}
if (isValid) {
// Process optional parameters
}
return isValid;
}
}
Then from our input controller, we can look and valid the required forms
public class FormController ... {
private Map<String, Validator> validators;
public void validForm(String formName, Properties formProperties) {
boolean isValid = false;
Validator validator = validators.get(formName);
if (validator != null) {
isValid = validate.isValid(formProperties);
}
return isValid;
}
}
Of course you need to provide some way to register the Validators and there may be differences based on the backbone framework you are using and the parameters you can use (you don't have to use Properties, but it is basically just a Map<String, String>...)
You can write something like this... it takes name of a class as string as an argument, the method name and its arguments
private static String invoke(String aClass, String aMethod, Class<?>[] params,
Object[] args) throws Exception {
String resp = "";
Class<?> c = Class.forName(aClass);
Method m = c.getDeclaredMethod(aMethod, params);
Object i = c.newInstance();
resp = m.invoke(i, args).toString();
return resp;
}
You can also refer to the oracle tutorial on reflection ... which demonstrates how to call methods
http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
It's possible using reflection.
First, you create a new class from the FQN (fully qualified name, which is the class name including the package).
Then you iterate through your elements and invoke the "validate" methods on your item.
Class<?> clazz = Class.forName("com.foo.Bar");
Object item = clazz.newInstance();
for (String element : elements) {
Method method = clazz.getDeclaredMethod("validate" + element);
method.invoke(item);
}
You can use reflection, but my favorite method is to use beanutils, eg:
Bar b1 = //...
BeanUtils.getProperty(b1, "first");
BeanUtils.getProperty(b1, "last");
Note that your class has to conform to javabean convention. You can read more about beanutils on this blog post (disclaimer I'm the blog author)
If you know the name of the class beforehand, use Class.forName(yourClassname)
That way, you can invoke the class, and then, you can invoke its methods.
Yes, using reflection.
Using Class.getDeclaredMethod on your object
Object validator = <your object instance>;
final String[] values = {
"Item1","Item2","Item3"
}
for(final String s : values) {
Method m = validator.getDeclaredMethod("validate" + s,String.class);
try {
Object result = m.invoke(validator, s);
}
catch(ex) {}
}
I was only aware of dynamic proxy being used for AOP.
However,it seems it can be used for lazy loading too.
The following example from an articles is intended to demonstrate that.
However I fail to understand how this is different from a normal accessor and what exactly is being 'lazily' loaded here?
Any help in understanding what the author intended to mean by lazy-loading is appreciated.
private Category tupleToObject(Serializable[] tuple) {
Category category = new Category((String)tuple[1],
(YearMonthDay) tuple[2]);
category.setId((Long) tuple[0]);
category.setParent(lazyGet((Long) tuple[3]));
return category;
}
protected CategoryItf lazyGet(Long id) {
if (id == null) {
return null;
}
return (CategoryItf)Proxy.newProxyInstance(
CategoryItf.class.getClassLoader(),
new Class[] { CategoryItf.class },
new LazyLoadedObject() {
protected Object loadObject() {
return get(id);
}
});
}
public abstract class LazyLoadedObject implements InvocationHandler {
private Object target;
public Object invoke(Object proxy,
Method method, Object[] args)
throws Throwable {
if (target == null) {
target = loadObject();
}
return method.invoke(target, args);
}
protected abstract Object loadObject();
}
How woul this be any different from the following:
private Category tupleToObject(Serializable[] tuple) {
Category category = new Category((String)tuple[1],
(YearMonthDay) tuple[2]);
category.setId((Long) tuple[0]);
category.setParent(get((Long) tuple[3]));
return category;
}
In both cases,the parent is created only when needed.
The following code snippet makes the implementation "lazy":
private Object target;
public Object invoke(Object proxy,
Method method, Object[] args)
throws Throwable {
if (target == null) {
target = loadObject();
}
You can see that no matter how many times you are calling this code you get the same object every time. So, practically it is singleton. However it is not created in the beginning of the program but only when it is needed first time. This is the meaning of "lazy" here.
Let me try to explain from how I understand the code:
In this code:
private Category tupleToObject(Serializable[] tuple) {
Category category = new Category((String)tuple[1],
(YearMonthDay) tuple[2]);
category.setId((Long) tuple[0]);
category.setParent(get((Long) tuple[3]));
return category;
}
the get() method will directly return the actual object, hence calling tupleToObject() will populate category parent with the actual object.
while in this code:
private Category tupleToObject(Serializable[] tuple) {
Category category = new Category((String)tuple[1],
(YearMonthDay) tuple[2]);
category.setId((Long) tuple[0]);
category.setParent(lazyGet((Long) tuple[3]));
return category;
}
the lazyGet() method actually returns a proxy (NOT the actual object). First method call on the proxy will actually trigger the loading of the object. The proxy here is used to delay the actual retrieval of the actual object until its actually needed i.e. lazy loading.
Hope this answers your question.
I need to compare dozens of fields in two objects (instances of the same class), and do some logging and updating in case there are differences. Meta code could look something like this:
if (a.getfield1 != b.getfield1)
log(a.getfield1 is different than b.getfield1)
b.field1 = a.field1
if (a.getfield2!= b.getfield2)
log(a.getfield2 is different than b.getfield2)
b.field2 = a.field2
...
if (a.getfieldn!= b.getfieldn)
log(a.getfieldn is different than b.getfieldn)
b.fieldn = a.fieldn
The code with all the comparisons is very terse, and I would like to somehow make it more compact. It would be nice if I could have a method which would take as a parameter method calls to setter and getter, and call this for all fields, but unfortunately this is not possible with java.
I have come up with three options, each which their own drawbacks.
1. Use reflection API to find out getters and setters
Ugly and could cause run time errors in case names of fields change
2. Change fields to public and manipulate them directly without using getters and setters
Ugly as well and would expose implementation of the class to external world
3. Have the containing class (entity) do the comparison, update changed fields and return log message
Entity should not take part in business logic
All fields are String type, and I can modify code of the class owning the fields if required.
EDIT: There are some fields in the class which must not be compared.
Use Annotations.
If you mark the fields that you need to compare (no matter if they are private, you still don't lose the encapsulation, and then get those fields and compare them. It could be as follows:
In the Class that need to be compared:
#ComparableField
private String field1;
#ComparableField
private String field2;
private String field_nocomparable;
And in the external class:
public <T> void compare(T t, T t2) throws IllegalArgumentException,
IllegalAccessException {
Field[] fields = t.getClass().getDeclaredFields();
if (fields != null) {
for (Field field : fields) {
if (field.isAnnotationPresent(ComparableField.class)) {
field.setAccessible(true);
if ( (field.get(t)).equals(field.get(t2)) )
System.out.println("equals");
field.setAccessible(false);
}
}
}
}
The code is not tested, but let me know if helps.
The JavaBeans API is intended to help with introspection. It has been around in one form or another since Java version 1.2 and has been pretty usable since version 1.4.
Demo code that compares a list of properties in two beans:
public static void compareBeans(PrintStream log,
Object bean1, Object bean2, String... propertyNames)
throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
Set<String> names = new HashSet<String>(Arrays
.asList(propertyNames));
BeanInfo beanInfo = Introspector.getBeanInfo(bean1
.getClass());
for (PropertyDescriptor prop : beanInfo
.getPropertyDescriptors()) {
if (names.remove(prop.getName())) {
Method getter = prop.getReadMethod();
Object value1 = getter.invoke(bean1);
Object value2 = getter.invoke(bean2);
if (value1 == value2
|| (value1 != null && value1.equals(value2))) {
continue;
}
log.format("%s: %s is different than %s%n", prop
.getName(), "" + value1, "" + value2);
Method setter = prop.getWriteMethod();
setter.invoke(bean2, value2);
}
}
if (names.size() > 0) {
throw new IllegalArgumentException("" + names);
}
}
Sample invocation:
compareBeans(System.out, bean1, bean2, "foo", "bar");
If you go the annotations route, consider dumping reflection and generating the comparison code with a compile-time annotation processor or some other code generator.
I would go for option 1, but I would use getClass().getDeclaredFields() to access the fields instead of using the names.
public void compareAndUpdate(MyClass other) throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
if (field.getType() == String.class) {
Object thisValue = field.get(this);
Object otherValue = field.get(other);
// if necessary check for null
if (!thisValue.equals(otherValue)) {
log(field.getName() + ": " + thisValue + " <> " + otherValue);
field.set(other, thisValue);
}
}
}
}
There are some restrictions here (if I'm right):
The compare method has to be implemented in the same class (in my opinion it should - regardless of its implementation) not in an external one.
Just the fields from this class are used, not the one's from a superclass.
Handling of IllegalAccessException necessary (I just throw it in the example above).
This is probably not too nice either, but it's far less evil (IMHO) than either of the two alternatives you've proposed.
How about providing a single getter/setter pair that takes a numeric index field and then have getter/setter dereference the index field to the relevant member variable?
i.e.:
public class MyClass {
public void setMember(int index, String value) {
switch (index) {
...
}
}
public String getMember(int index) {
...
}
static public String getMemberName(int index) {
...
}
}
And then in your external class:
public void compareAndUpdate(MyClass a, MyClass b) {
for (int i = 0; i < a.getMemberCount(); ++i) {
String sa = a.getMember();
String sb = b.getMember();
if (!sa.equals(sb)) {
Log.v("compare", a.getMemberName(i));
b.setMember(i, sa);
}
}
}
This at least allows you to keep all of the important logic in the class that's being examined.
While option 1 may be ugly, it will get the job done. Option 2 is even uglier, and opens your code to vulnerabilities you can't imagine. Even if you eventually rule out option 1, I pray you keep your existing code and not go for option 2.
Having said this, you can use reflection to get a list of the field names of the class, if you don't want to pass this as a static list to the method. Assuming you want to compare all fields, you can then dynamically create the comparisons, in a loop.
If this isn't the case, and the strings you compare are only some of the fields, you can examine the fields further and isolate only those that are of type String, and then proceed to compare.
Hope this helps,
Yuval =8-)
since
All fields are String type, and I can modify code of the class owning the fields if required.
you could try this class:
public class BigEntity {
private final Map<String, String> data;
public LongEntity() {
data = new HashMap<String, String>();
}
public String getFIELD1() {
return data.get(FIELD1);
}
public String getFIELD2() {
return data.get(FIELD2);
}
/* blah blah */
public void cloneAndLogDiffs(BigEntity other) {
for (String field : fields) {
String a = this.get(field);
String b = other.get(field);
if (!a.equals(b)) {
System.out.println("diff " + field);
other.set(field, this.get(field));
}
}
}
private String get(String field) {
String value = data.get(field);
if (value == null) {
value = "";
}
return value;
}
private void set(String field, String value) {
data.put(field, value);
}
#Override
public String toString() {
return data.toString();
}
magic code:
private static final String FIELD1 = "field1";
private static final String FIELD2 = "field2";
private static final String FIELD3 = "field3";
private static final String FIELD4 = "field4";
private static final String FIELDN = "fieldN";
private static final List<String> fields;
static {
fields = new LinkedList<String>();
for (Field field : LongEntity.class.getDeclaredFields()) {
if (field.getType() != String.class) {
continue;
}
if (!Modifier.isStatic(field.getModifiers())) {
continue;
}
fields.add(field.getName().toLowerCase());
}
}
this class has several advantages:
reflects once, at class loading
it is very simply adding new fields, just add new static field (a better solution here
is using Annotations: in the case you care using reflection works also java 1.4)
you could refactor this class in an abstract class, all derived class just get both
data and cloneAndLogDiffs()
the external interface is typesafe (you could also easily impose immutability)
no setAccessible calls: this method is problematic sometimes
A broad thought:
Create a new class whose object takes the following parameters: the first class to compare, the second class to compare, and a lists of getter & setter method names for the objects, where only methods of interest are included.
You can query with reflection the object's class, and from that its available methods. Assuming each getter method in the parameter list is included in the available methods for the class, you should be able to call the method to get the value for comparison.
Roughly sketched out something like (apologies if it isn't super-perfect... not my primary language):
public class MyComparator
{
//NOTE: Class a is the one that will get the value if different
//NOTE: getters and setters arrays must correspond exactly in this example
public static void CompareMyStuff(Object a, Object b, String[] getters, String[] setters)
{
Class a_class = a.getClass();
Class b_class = b.getClass();
//the GetNamesFrom... static methods are defined elsewhere in this class
String[] a_method_names = GetNamesFromMethods(a_class.getMethods());
String[] b_method_names = GetNamesFromMethods(b_class.getMethods());
String[] a_field_names = GetNamesFromFields(a_class.getFields());
//for relative brevity...
Class[] empty_class_arr = new Class[] {};
Object[] empty_obj_arr = new Object[] {};
for (int i = 0; i < getters.length; i++)
{
String getter_name = getter[i];
String setter_name = setter[i];
//NOTE: the ArrayContainsString static method defined elsewhere...
//ensure all matches up well...
if (ArrayContainsString(a_method_names, getter_name) &&
ArrayContainsString(b_method_names, getter_name) &&
ArrayContainsString(a_field_names, setter_name)
{
//get the values from the getter methods
String val_a = a_class.getMethod(getter_name, empty_class_arr).invoke(a, empty_obj_arr);
String val_b = b_class.getMethod(getter_name, empty_class_arr).invoke(b, empty_obj_arr);
if (val_a != val_b)
{
//LOG HERE
//set the value
a_class.getField(setter_name).set(a, val_b);
}
}
else
{
//do something here - bad names for getters and/or setters
}
}
}
}
You say you presently have getters and setters for all these fields? Okay, then change the underlying data from a bunch of individual fields to an array. Change all the getters and setters to access the array. I'd create constant tags for the indexes rather than using numbers for long-term maintainability. Also create a parallel array of flags indicating which fields should be processed. Then create a generic getter/setter pair that use an index, as well as a getter for the compare flag. Something like this:
public class SomeClass
{
final static int NUM_VALUES=3;
final static int FOO=0, BAR=1, PLUGH=2;
String[] values=new String[NUM_VALUES];
static boolean[] wantCompared={true, false, true};
public String getFoo()
{
return values[FOO];
}
public void setFoo(String foo)
{
values[FOO]=foo;
}
... etc ...
public int getValueCount()
{
return NUM_VALUES;
}
public String getValue(int x)
{
return values[x];
}
public void setValue(int x, String value)
{
values[x]=value;
}
public boolean getWantCompared(int x)
{
return wantCompared[x];
}
}
public class CompareClass
{
public void compare(SomeClass sc1, SomeClass sc2)
{
int z=sc1.getValueCount();
for (int x=0;x<z;++x)
{
if (!sc1.getWantCompared[x])
continue;
String sc1Value=sc1.getValue(x);
String sc2Value=sc2.getValue(x);
if (!sc1Value.equals(sc2Value)
{
writeLog(x, sc1Value, sc2Value);
sc2.setValue(x, sc1Value);
}
}
}
}
I just wrote this off the top of my head, I haven't tested it, so their may be bugs in the code, but I think the concept should work.
As you already have getters and setters, any other code using this class should continue to work unchanged. If there is no other code using this class, then throw away the existing getters and setters and just do everything with the array.
I would also propose a similar solution to the one by Alnitak.
If the fields need to be iterated when comparing, why not dispense with the separate fields, and put the data into an array, a HashMap or something similar that is appropriate.
Then you can access them programmatically, compare them etc. If different fields need to be treated & compared in different ways, you could create approriate helper classes for the values, which implement an interface.
Then you could just do
valueMap.get("myobject").compareAndChange(valueMap.get("myotherobject")
or something along those lines...