I am using Tapestry 5.3.6 for a web application and I want the user to edit an instance of a Java class (a "bean", or POJO) using a web form (which immediately suggests the use of beaneditform) - however the Java class to be edited has a fairly complex structure. I am looking for the simplest way of doing this in Tapestry 5.
Firstly, lets define some utility classes e.g.
public class ModelObject {
private URI uri;
private boolean modified;
// the usual constructors, getters and setters ...
}
public class Literal<T> extends ModelObject {
private Class<?> valueClass;
private T value;
public Literal(Class<?> valueClass) {
this.valueClass = valueClass;
}
public Literal(Class<?> valueClass, T value) {
this.valueClass = valueClass;
this.value = value;
}
// the usual getters and setters ...
}
public class Link<T extends ModelObject> extends ModelObject {
private Class<?> targetClass;
private T target;
public Link(Class<?> targetClass) {
this.targetClass = targetClass;
}
public Link(Class<?> targetClass, T target) {
this.targetClass = targetClass;
this.target = target;
}
// the usual getters and setters ...
}
Now you can create some fairly complex data structures, for example:
public class HumanBeing extends ModelObject {
private Literal<String> name;
// ... other stuff
public HumanBeing() {
name = new Literal<String>(String.class);
}
// the usual getters and setters ...
}
public class Project extends ModelObject {
private Literal<String> projectName;
private Literal<Date> startDate;
private Literal<Date> endDate;
private Literal<Integer> someCounter;
private Link<HumanBeing> projectLeader;
private Link<HumanBeing> projectManager;
// ... other stuff, including lists of things, that may be Literals or
// Links ... e.g. (ModelObjectList is an enhanced ArrayList that remembers
// the type(s) of the objects it contains - to get around type erasure ...
private ModelObjectList<Link<HumanBeing>> projectMembers;
private ModelObjectList<Link<Project>> relatedProjects;
private ModelObjectList<Literal<String>> projectAliases;
// the usual constructors, getters and setters for all of the above ...
public Project() {
projectName = new Literal<String>(String.class);
startDate = new Literal<Date>(Date.class);
endDate = new Literal<Date>(Date.class);
someCounter = new Literal<Integer>(Integer.class);
projectLeader = new Link<HumanBeing>(HumanBeing.class);
projectManager = new Link<HumanBeing>(HumanBeing.class);
projectMembers = new ModelObjectList<Link<HumanBeing>>(Link.class, HumanBeing.class);
// ... more ...
}
}
If you point beaneditform at an instance of Project.class, you will not get very far before you have to supply a lot of custom coercers, translators, valueencoders, etc - and then you still run into the problem that you can't use generics when "contributing" said coercers, translators, valueencoders, etc.
I then started writing my own components to get around these problems (e.g. ModelObjectDisplay and ModelObjectEdit) but this would require me to understand a lot more of the guts of Tapestry than I have time to learn ... it feels like I might be able to do what I want using the standard components and liberal use of "delegate" etc. Can anyone see a simple path for me to take with this?
Thanks for reading this far.
PS: if you are wondering why I have done things like this, it is because the model represents linked data from an RDF graph database (aka triple-store) - I need to remember the URI of every bit of data and how it relates (links) to other bits of data (you are welcome to suggest better ways of doing this too :-)
EDIT:
#uklance suggested using display and edit blocks - here is what I had already tried:
Firstly, I had the following in AppPropertyDisplayBlocks.tml ...
<t:block id="literal">
<t:delegate to="literalType" t:value="literalValue" />
</t:block>
<t:block id="link">
<t:delegate to="linkType" t:value="linkValue" />
</t:block>
and in AppPropertyDisplayBlocks.java ...
public Block getLiteralType() {
Literal<?> literal = (Literal<?>) context.getPropertyValue();
Class<?> valueClass = literal.getValueClass();
if (!AppModule.modelTypes.containsKey(valueClass))
return null;
String blockId = AppModule.modelTypes.get(valueClass);
return resources.getBlock(blockId);
}
public Object getLiteralValue() {
Literal<?> literal = (Literal<?>) context.getPropertyValue();
return literal.getValue();
}
public Block getLinkType() {
Link<?> link = (Link<?>) context.getPropertyValue();
Class<?> targetClass = link.getTargetClass();
if (!AppModule.modelTypes.containsKey(targetClass))
return null;
String blockId = AppModule.modelTypes.get(targetClass);
return resources.getBlock(blockId);
}
public Object getLinkValue() {
Link<?> link = (Link<?>) context.getPropertyValue();
return link.getTarget();
}
AppModule.modelTypes is a map from java class to a String to be used by Tapestry e.g. Link.class -> "link" and Literal.class -> "literal" ... in AppModule I had the following code ...
public static void contributeDefaultDataTypeAnalyzer(
MappedConfiguration<Class<?>, String> configuration) {
for (Class<?> type : modelTypes.keySet()) {
String name = modelTypes.get(type);
configuration.add(type, name);
}
}
public static void contributeBeanBlockSource(
Configuration<BeanBlockContribution> configuration) {
// using HashSet removes duplicates ...
for (String name : new HashSet<String>(modelTypes.values())) {
configuration.add(new DisplayBlockContribution(name,
"blocks/AppPropertyDisplayBlocks", name));
configuration.add(new EditBlockContribution(name,
"blocks/AppPropertyEditBlocks", name));
}
}
I had similar code for the edit blocks ... however none of this seemed to work - I think because the original object was passed to the "delegate" rather than the de-referenced object which was either the value stored in the literal or the object the link pointed to (hmm... should be [Ll]inkTarget in the above, not [Ll]inkValue). I also kept running into errors where Tapestry couldn't find a suitable "translator", "valueencoder" or "coercer" ... I am under some time pressure so it is difficult to follow these twisty passages through in order to get out of the maze :-)
I would suggest to build a thin wrapper around the Objects you would like to edit though the BeanEditForm and pass those into it. So something like:
public class TapestryProject {
private Project project;
public TapestryProject(Project proj){
this.project = proj;
}
public String getName(){
this.project.getProjectName().getValue();
}
public void setName(String name){
this.project.getProjectName().setValue(name);
}
etc...
}
This way tapestry will deal with all the types it knows about leaving you free of having to create your own coersions (which is quite simple in itself by the way).
You can contribute blocks to display and edit your "link" and "literal" datatypes.
The beaneditform, beaneditor and beandisplay are backed by the BeanBlockSource service. BeanBlockSource is responsible for providing display and edit blocks for various datatypes.
If you download the tapestry source code and have a look at the following files:
tapestry-core\src\main\java\org\apache\tapestry5\corelib\pages\PropertyEditBlocks.java
tapestry-core\src\main\resources\org\apache\tapestry5\corelib\pages\PropertyEditBlocks.tml
tapestry-core\src\main\java\org\apache\tapestry5\services\TapestryModule.java
You will see how tapestry contributes EditBlockContribution and DisplayBlockContribution to provide default blocks (eg for a "date" datatype).
If you contribute to BeanBlockSource, you could provide display and edit blocks for your custom datatypes. This will require you reference blocks by id in a page. The page can be hidden from your users by annotating it with #WhitelistAccessOnly.
http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/BeanBlockSource.html
http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/DisplayBlockContribution.html
http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/EditBlockContribution.html
http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html
Here's an example of using an interface and a proxy to hide the implementation details from your model. Note how the proxy takes care of updating the modified flag and is able to map URI's from the Literal array to properties in the HumanBeing interface.
package com.github.uklance.triplestore;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
public class TripleStoreOrmTest {
public static class Literal<T> {
public String uri;
public boolean modified;
public Class<T> type;
public T value;
public Literal(String uri, Class<T> type, T value) {
super();
this.uri = uri;
this.type = type;
this.value = value;
}
#Override
public String toString() {
return "Literal [uri=" + uri + ", type=" + type + ", value=" + value + ", modified=" + modified + "]";
}
}
public interface HumanBeing {
public String getName();
public void setName(String name);
public int getAge();
public void setAge();
}
public interface TripleStoreProxy {
public Map<String, Literal<?>> getLiteralMap();
}
#Test
public void testMockTripleStore() {
Literal<?>[] literals = {
new Literal<String>("http://humanBeing/1/Name", String.class, "Henry"),
new Literal<Integer>("http://humanBeing/1/Age", Integer.class, 21)
};
System.out.println("Before " + Arrays.asList(literals));
HumanBeing humanBeingProxy = createProxy(literals, HumanBeing.class);
System.out.println("Before Name: " + humanBeingProxy.getName());
System.out.println("Before Age: " + humanBeingProxy.getAge());
humanBeingProxy.setName("Adam");
System.out.println("After Name: " + humanBeingProxy.getName());
System.out.println("After Age: " + humanBeingProxy.getAge());
Map<String, Literal<?>> literalMap = ((TripleStoreProxy) humanBeingProxy).getLiteralMap();
System.out.println("After " + literalMap);
}
protected <T> T createProxy(Literal<?>[] literals, Class<T> type) {
Class<?>[] proxyInterfaces = { type, TripleStoreProxy.class };
final Map<String, Literal> literalMap = new HashMap<String, Literal>();
for (Literal<?> literal : literals) {
String name = literal.uri.substring(literal.uri.lastIndexOf("/") + 1);
literalMap.put(name, literal);
}
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass().equals(TripleStoreProxy.class)) {
return literalMap;
}
if (method.getName().startsWith("get")) {
String name = method.getName().substring(3);
return literalMap.get(name).value;
} else if (method.getName().startsWith("set")) {
String name = method.getName().substring(3);
Literal<Object> literal = literalMap.get(name);
literal.value = args[0];
literal.modified = true;
}
return null;
}
};
return type.cast(Proxy.newProxyInstance(getClass().getClassLoader(), proxyInterfaces, handler));
}
}
Related
I am in a situation, where I'm trying to implement a (relatively simple) abstract syntax tree. All of the nodes inherit from a type called SimpleNode containing some code to store line and column information and accepting a visitor.
Now, some of the nodes should also be nameable, while others should have a property "accessible" (eg. public or private). Some nodes should even support both interfaces.
I'd preferably implement this using virtual inheritance and write two classes NameableNode and AccessibleNode, but Java doesn't support MI.
Eg NameableNode might have field "name" and implement simple getters and setters for this field. Similarly, AccessibleNode might also have a field "accessibility" and getters/setters.
What is a good way to implement this and avoid introducing code duplication in a huge part of the code base?
Small code example:
public class SimpleNode {
private int line = 0;
private int column = 0;
/* Getters and setters for line/column. */
/* ... */
}
public class NameableNode extends SimpleNode {
private String name = "";
/* Getters and setters for name */
}
public class AccessibleNode extends SimpleNode {
private boolean isPublic = false;
/* Getters and setters for accessibility */
}
You're looking for composition. There are many flavors of this - I will propose one that, from my understanding of what you're trying to build, should suit your purpose.
First, let's create some interfaces for yours Nodes:
public interface Nameable {
/* Getters and setters for name */
}
public interface Accessible {
/* Getters and setters for accessibility */
}
Next, you probably don't want to repeat the same implementation for every Node, so let's create those implementations:
public class NameDelegate() {
private String name = "";
/* Getters and setters for name */
}
public class AccessDelegate() {
private boolean isPublic = false;
/* Getters and setters for accessibility */
}
Now, let's put everything together:
public class SomeNodeA extends SimpleNode implements Nameable {
private NameDelegate nameDelegate;
public SomeNodeA(NameDelegate nameDelegate) {
this.nameDelegate = nameDelegate;
}
#Override
public String getName() {
return nameDelegate.getName();
}
#Override
public String setName(String name) {
nameDelegate.setName(name);
}
}
You can also have both behaviours in a single class:
public class SomeNodeB extends SimpleNode implements Nameable, Accessible {
private NameDelegate nameDelegate;
private AccessDelegate accessDelegate;
public SomeNodeB(NameDelegate nameDelegate, AccessDelegate accessDelegate) {
this.nameDelegate = nameDelegate;
this.accessDelegate = accessDelegate;
}
#Override
public String getName() {
return nameDelegate.getName();
}
#Override
public String setName(String name) {
nameDelegate.setName(name);
}
#Override
public boolean getAccessibility() {
return accessDelegate.getAccessibility();
}
/* etc... */
}
The idea is, you can package the state and the functionality of the different "features" into individual delegates, and expose them as corresponding interfaces in your Nodes.
Also, when operating on the Nodes, if you need to know whether a given instance of a Node supports a specific feature, you can use instanceof - e.g.:
if (someNode instanceof Nameable) {
// do naming stuff
}
In this case I would use the composition approach over inheritance:
public class Node {
private int line = 0;
private int column = 0;
/* Getters and setters for line/column. */
/* ... */
private String name = null;
public String getName() {
return this.name;
}
public void setName(String name) {
this._name = name;
}
private Boolean _isPublic = null;
public String isPublic() {
return this.name;
}
public void setIsPublic(boolean isPublic) {
this._isPublic = isPublic;
}
public boolean hasAccessibility() {
return this._isPublic != null;
}
public boolean hasName() {
return this._name != null;
}
}
Another solution that I like a bit more is creating these attributes dynamically using a HashMap and an enum that indicates all the possible attributes of a node. This way is more generic, as it requires to write less code for supporting new attributes, But it is also less typesafe(ish), as the additional attributes need to be casted at runtime:
import java.util.HashMap;
enum NodeAttribute {
NAME,
ACCESSIBILTY
}
enum NodeAccessibility {
PUBLIC,
PRIVATE
}
public class Node {
private int line = 0;
private int column = 0;
// Notice that this Object usage might involve some boxing for attributes of premitive type
private HashMap<NodeAttribute, Object> additionalAttributes = new HashMap<NodeAttribute, Object>();
/* Getters and setters for line/column. */
/* ... */
public boolean hetAttribute(NodeAttribute attribute) {
return this.additionalAttributes.containsKey(attribute);
}
public <T> T getAttributeValue(NodeAttribute attribute, Class<T> attributeClass) {
Object attributeValue = this.additionalAttributes.get(attribute);
// You may want to wrap the ClassCastException that may be raisen here to a more specfic error
T castedAttributeValue = attributeClass.cast(attributeValue);
return castedAttributeValue;
}
public void setAttributeValue(NodeAttribute attribute, Object value) {
// Notice that this implemintation allows changing the type of an existing attribute,
// If this is invalid behavior in your case you can throw an exception instead
this.additionalAttributes.put(attribute, value);
}
}
// Example usage
public class Program {
public static void main(String[] args) {
Node nodeWithNameOnly = new Node();
nodeWithNameOnly.setAttributeValue(NodeAttribute.NAME, 'node1');
Node nodeWithBoth = new Node();
nodeWithBoth.setAttributeValue(NodeAttribute.NAME, 'node2');
nodeWithBoth.setAttributeValue(NodeAttribute.ACCESSIBILTY, NodeAccessibility.PRIVATE);
Program.doStuffWithNode(nodeWithNameOnly);
/* output:
Node name: node1
*/
Program.doStuffWithNode(nodeWithBoth);
/* output:
Node name: node2
Node is public: False
*/
}
public static void doStuffWithNode(Node node) {
if (nodeWithNameOnly.hetAttribute(NodeAttribute.NAME)) {
String nodeName = nodeWithNameOnly.getAttributeValue(NodeAttribute.NAME, String.class);
system.out.println("Node name: " + nodeName);
}
if (nodeWithNameOnly.hetAttribute(NodeAttribute.ACCESSIBILTY)) {
NodeAccessibility nodeAccessibilty =
nodeWithNameOnly.getAttributeValue(NodeAttribute.ACCESSIBILTY, NodeAccessibility.class);
boolean nodeIsPublic = nodeAccessibilty == NodeAccessibility.PUBLIC;
system.out.println("Node is public: " + String.valueOf(nodeIsPublic));
}
}
}
In any case, this is the main rule of thumb - Inheritance should be used for an "is a" relation, whereas composition should be used for an "has a" relation.
For instance:
Fish extends Animal because a Fish is an Animal.
Post holds comments because a Post has comments.
And in our case, a node has a name and an accessibility level so it should hold them.
I have a POJO named Document.java with 100+ member variables. There is a transformation layer, where I get the required data, transform it and store it in the Document class.
In the tranformation layer, I would like to set a member variable only if satisfies a certain criteria (based on available context).
So it would look something like this:
if(shouldGetExecuted1(context.getXXX())){
document.setField1(tranformDataForField1(availableData1));
}
if(shouldGetExecuted2(context.getXXX())){
document.setField2(tranformDataForField2(availableData2));
}
I want to do this for all the 100+ fields. Is there a clean way to do this?
Additional information
I don't want to use Strategy here as it would create too many classes as the no of strategies grow.
Try to use AOP. AspectJ allows you to define pointcuts (for example, some filtered set of methods) and control their execution via advices (before method call, after, around):
#Aspect
class ClassName {
...
#PointCut("call(public void ClassName.*(..))") //includes all void methods of ClassName object
public void myPointCut(){}
#Around("myPointCut()")
public void myLogicMethod(ProceedingJoinPoint thisJoinPoint) {
if(shouldGetExecuted1(context.getXXX())){
thisJoinPoint.proceed()
}
}
}
Here thisJoinPoint.proceed() will execute the body of the intercepted method.
Read docs about how to define pointcuts. In this example the same logic will be applied to all void methods of this class. You can define more accurate pointcuts via special expressions to provide different logic for each.
No, there is no clean way to do it in Java. You can find methods using reflection but there is no way to find variables such as "availableDataN". So you necessarily need to make "availableDataN" a field in order to find it using reflection.
The final code would be something as ugly as the following:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class X {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Method shouldGetExecuted = X.class.getMethod("shouldGetExecuted" + i, String.class);
boolean b = (boolean) shouldGetExecuted.invoke(null, context.getXXX());
if (b) {
Method tranformDataForField = X.class.getMethod("tranformDataForField");
Field data = X.class.getField("availableData" + i);
Object result = tranformDataForField.invoke(null, data.get(null));
Method set = X.class.getMethod("setField" + i, TransformDataType.class);
set.invoke(null, result);
}
}
}
}
You need to adapt to your specific case. For instance, here I am assuming all fields and methods are static. If they are not, then you need to replace null with an instance reference.
If you are consistent in the naming of your methods, reflection could help a lot.
The following code assumes the following:
A Document class with fields like xxx or xxYy (getters/setters would be usually present but are not required for the code to work)
A Transformer class that has
the capability to determine based on context information, if a field should be processed. These methods are named shouldTransformXxx(context).
the capability to transform the content of the field (with input and output of the same type as the corresponding field in Document). These methods are named T transformXxx(T).
A DataProvider class that has methods to provide the untransformed data. these methods are named findXxx()
The code below is pretty optimistic - it will fail, if a shouldTransformXxx for any field misses, or if it returns true, the same applies for the findXxx and transformXxx methods. So you would have to create classes with 100 methods each, which seems non-ideal for me. But on the other hand, having a class with 100 members seems to lead to awkward situations anyway...
So here's the code:
public class Document {
private String name;
private int size;
#Override
public String toString() {
return "Document [name=" + name + ", size=" + size + "]";
}
}
public class Transformer {
public enum ContextType {
NAME, SIZE
}
public boolean shouldTransformName(Set<ContextType> context) {
return context.contains(ContextType.NAME);
}
public boolean shouldTransformSize(Set<ContextType> context) {
return context.contains(ContextType.SIZE);
}
public String transformName(String name) {
return "::" + name;
}
public int transformSize(int size) {
return size + 1;
}
}
public class DataProvider {
private final String name;
private final int size;
public DataProvider(String name, int size) {
this.name = name;
this.size = size;
}
public String findName() {
return name;
}
public int findSize() {
return size;
}
}
public class Main {
private static final String TRANSFORM_METHOD_PREFIX = "transform";
private static final String CHECK_METHOD_PREFIX = "shouldTransform";
private static final String DATAPROVIDER_METHOD_PREFIX = "find";
private final DataProvider dataProvider;
private final Transformer transformer;
public Main(DataProvider dataProvider, Transformer transformer) {
this.dataProvider = dataProvider;
this.transformer = transformer;
}
public Document transformFields(Set<ContextType> context)
throws ReflectiveOperationException {
Document document = new Document();
for (Field field : Document.class.getDeclaredFields()) {
String capitalizedfieldName = capitalize(field.getName());
Class<?> fieldType = field.getType();
if (shouldTransform(context, capitalizedfieldName)) {
Object data = findData(capitalizedfieldName);
Object transformed = transformData(capitalizedfieldName,
fieldType, data);
// in presence of a security manager, a reflective call of the
// setter could be performed
field.setAccessible(true);
field.set(document, transformed);
}
}
return document;
}
private Object transformData(String capitalizedfieldName,
Class<?> fieldType, Object data)
throws ReflectiveOperationException {
String methodName = TRANSFORM_METHOD_PREFIX + capitalizedfieldName;
Method method = Transformer.class.getMethod(methodName, fieldType);
return method.invoke(transformer, data);
}
private Object findData(String capitalizedfieldName)
throws ReflectiveOperationException {
String methodName = DATAPROVIDER_METHOD_PREFIX + capitalizedfieldName;
Method method = DataProvider.class.getMethod(methodName);
return method.invoke(dataProvider);
}
private boolean shouldTransform(Set<ContextType> context,
String capitalizedfieldName) throws ReflectiveOperationException {
String methodName = CHECK_METHOD_PREFIX + capitalizedfieldName;
Method method = Transformer.class.getMethod(methodName, Set.class);
return (Boolean) method.invoke(transformer, context);
}
private String capitalize(String fieldName) {
char upperCaseFirstChar = Character.toUpperCase(fieldName.charAt(0));
if (fieldName.length() > 1) {
return upperCaseFirstChar + fieldName.substring(1);
} else {
return Character.toString(upperCaseFirstChar);
}
}
public static void main(String[] args) throws ReflectiveOperationException {
DataProvider dataProvider = new DataProvider("sample", 1);
Set<ContextType> context = EnumSet.of(ContextType.NAME,
ContextType.SIZE);
Main main = new Main(dataProvider, new Transformer());
Document document = main.transformFields(context);
System.out.println(document);
}
}
I was wondering if the following scenario is possible.
Having two classes (Source and Destination) where in code I could do this:
public class Source{
private String fieldA;
private String fieldB;
public Source(){ ... }
}
...
public class Destination{
public Destination(Source src){ ... }
}
Source src = new Source();
Destination dest = new Destination(src);
dest.fieldA = "test";
dest.fieldB = "test";
So what I mean here is that I have two classes, one called Source that contains (private) fields and one called Destination with no fields. After creating two objects of these classes and passing in Source into the constructor of Destination, I want to be able to duplicate/copy the fields of Source into Destination.
Could something like this be possible in Java, whether or not using Reflection? And if possible, can someone give me a minor example I can start with.
A hackish version to accomplish this is to add all fields to a Map. The fields can be copied from the source object to the destination object and the field name can be the key. Something along the lines of this:
public class FieldAccessor {
public static class Destination {
private final Map<String, Object> fields = new HashMap<>();
public Destination(Object o) {
final Set<Field> accessibleFields = Arrays.stream(o.getClass().getDeclaredFields())
.map(field -> {
field.setAccessible(true);
return field;
})
.collect(Collectors.toSet());
accessibleFields.forEach(field -> {
try {
fields.put(field.getName(), field.get(o));
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unable to access field", e);
}
});
}
public Set<String> fieldNames() {
return fields.keySet();
}
public Optional<Object> fieldValue(String fieldName) {
return Optional.ofNullable(fields.get(fieldName));
}
}
public static class Source {
private final String fieldA;
private final Integer fieldB;
private final int fieldC;
public Source(String fieldA, Integer fieldB, int fieldC) {
this.fieldA = fieldA;
this.fieldB = fieldB;
this.fieldC = fieldC;
}
public String getFieldA() {
return fieldA;
}
public Integer getFieldB() {
return fieldB;
}
public int getFieldC() {
return fieldC;
}
}
#Test
public void testFields() {
Destination destination = new Destination(new Source("Abc", 123, 456));
destination.fieldNames().stream().forEach(fieldName -> {
System.out.println("Fieldname: " + fieldName + ", value: " + destination.fieldValue(fieldName).get());
});
}
}
For more info, check out this SO.
However, this is not something I would use in real production code. Instead, I would use some sort of serialization by e.g. using Jackson.
So you want to dynamically create fields in an object ? That's not directly possible in Java. If you just wanted to copy methods of an interface, the answer would have be to use a JDK proxy. It may still be of interest if :
you accept to only use getters and setters in Destination class
Source class implements an interface defining the setters and getters you want to copy
If you cannot accept those restrictions, you will have to look to CGLIB proxies or Javassist, that is libraries that dynamically modify the bytecode of the compiled class objects at load time. It is a really advanced feature, that is mainly used in frameworks or other libraries and not in high-level programs. Typically it is used in Object Relational Mappers like Hibernate to replace simple collection classes with enhanced ones that transparently gets (an save) their elements in database.
In any other case, trying to access private fields outside of the class should be seen as an indicator for a possible design flaw. private means implementation dependant and can change across versions and should not be used without knowing why.
The simplest and most efficient way to do it is copying the fields explicitly :
public Destination(Source src)
{
this.fieldA = src.getFieldA();
this.fieldB = src.getFieldB();
}
I don't see the point in using reflection for this purpose.
The only thing is in my mind for this at this time is extending Destination class from Source
public class Source{
private String fieldA;
private String fieldB;
//You need to have both Getter and Setter for fieldA and fieldB
public Source(){ ... }
}
...
public class Destination extends Source{
public Destination(){...}
}
Source src = new Destination();
dest.setFieldA("test");
dest.setFieldB("test");
Private members of Source cannot be accessed from Destination object even if you are passing a Source object to Destination.
You need to add string fieldA, fieldB to Destination to
string fieldA, fieldB;
public Destination(Source src)
{
fieldA = src.fieldA;
fieldB = src.fieldB;
}
For instance i have some entity - Product
public class Product {
...
private String name;
private int count;
private Product associatedProduct;
...
// GETTERS & SETTERS
}
And also i have product finder which allows to find the product by filters:
public interface Finder<T> {
Set<T> find(Filter... filters);
}
And now i can execute the following code:
Finder<Product> finder = ...;
// find all products with name 'cucumber'
Set<Product> finder.find(Filter.equals("name", "cucumber"));
We don't like this code because i should have the 'soft' link to field name "name" and i can't have compile time exception in case misprint or any other mistake.
For this reason i have created the code generator which generate static links to properties.
The generated class looks like:
public final class $Product {
private final String context;
// some factory is used to instance creation
$PostEntity() {this.context = "";}
$PostEntity(String context) {this.context = context;}
public String name() { return context + "name";}
public String count() { return context + "count";}
public String associatedProduct() { return context + "associatedProduct";}
public $Product associatedProductDot() { return new $Product( this.context + "associatedProduct.");}
}
For now i can make the following:
Set<Product> finder.find(Filter.equals(Links.PRODUCT.name() , "cucumber"));
//or
Set<Product> finder.find(Filter.equals(Links.PRODUCT.associatedProductDot().name() , "cucumber"));
It works like a charm and i happy.
I know alternative approach with using proxy objects, but it imposes additional overhead in runtime and adds some magical moment in code, so this variant does not suit me.
And finally my question:
There is a more elegant approach to implement this functionality with using java 8?
Java 8 has everything you need:
public static <C,P> Predicate<C> byProperty(Function<C,P> f, P value) {
return component->Objects.equals(f.apply(component), value);
}
public static <C> Set<C> find(Collection<? extends C> c, Predicate<? super C> p) {
return c.stream().filter(p).collect(Collectors.<C>toSet());
}
The standard interface for filtering is called Predicate and the first method above allows you to create arbitrary Predicates for matching a property of a component type C. The second method shows how you can get a Set of matching components out of a Collection using the Stream API. Then you can use it like this:
List<Product> list;
…
Set<Product> set=find(list, byProperty(Product::getName, "foo"));
or
Set<Product> set=find(list, byProperty(Product::getCount, 42));
Note that this is type safe and contains compile-time checked references (your “hard links”) to your properties. The only difference to what you have asked for is that they refer to the getter method rather than to the field names, as a) field references are not supported and b) your fields are private anyway.
Note that you can augment these methods by another factory allowing to provide a value-predicate rather than a constant:
public static <C,P> Predicate<C> matchProp(
Function<C,P> f, Predicate<? super P> value) {
return component->value.test(f.apply(component));
}
This allows use cases like:
Set<Product> set=find(list, matchProp(Product::getCount, count -> count>100));
See Lambda Expressions
or
Set<Product> set=find(list, matchProp(Product::getName, String::isEmpty));
The fastest thing is to provide your own implementation of the Filter interface. Since I don't know your Filter interface, I have to make an assumption about how it looks like. Here is my assumption:
public interface Filter<T> {
boolean matches(T t);
}
By the way, I think the interface Finder should instead look like this:
public interface Finder<T> {
Set<T> find(Filter<? super T>... filters);
}
So, you could have a class like this:
public final class ProductFilters {
private ProductFilters() { /* Utility class */ }
public static Filter<Product> byName(final String name) {
return new Filter() {
public boolean matches(Product t) {
return name.equals(t.getName());
}
}
}
}
You could even put this inside class Product, which can make it a little bit nicer:
public class Product {
private String name;
public static final class Filters {
private Filters() { /* Utility Class */ }
public static Filter<Product> byName(final String name) {
return new Filter() {
public boolean matches(final Product t) {
return name.equals(t.name);
}
};
}
}
}
And yes, Java 8 makes this stuff nicer, the explicit anonymous class can syntactically be replaced by a lambda, like this:
public class Product {
private String name;
public static final class Filters {
private Filters() { /* Utility Class */ }
public static Filter<Product> byName(final String name) {
return t -> name.equals(t.name);
}
}
}
Your code that uses the filters could now look like this:
Set<Product> cucumbers = finder.find(Product.Filters.byName("cucumber"));
The Filter<T> interface is present in Java 8 in package java.util.function. It's name there is Predicate<T>, and the essential part looks like this:
public interface Predicate<T> {
boolean test(T t);
}
If the products that are to be filtered can be made available as Stream either directly, or via a Collection, you can use the new java.util.stream API for filtering. For the example I assume that the products to be filtered are in a Set, too. The code that filters products could look like this:
Set<Product> potentialCucumbers = ...;
// Inline lambda:
Set<Product> cucumbers = potentialCucumbers.stream().filter(p -> "cucumber".equals(p.getName())).collect(Collectors.toSet());
// Stored lambda as above:
Set<Product> cucumbers = potentialCucumbers.stream().filter(Product.Filters.byName("cucumber")).collect(Collectors.toSet());
I really like static imports for that stuff as they can significantly reduce line length. With static imports it looks like this:
Set<Product> potentialCucumbers = ...;
// Inline lambda:
Set<Product> cucumbers = potentialCucumbers.stream().filter(p -> "cucumber".equals(p.getName())).collect(toSet());
// Stored lambda as above:
Set<Product> cucumbers = potentialCucumbers.stream().filter(byName("cucumber")).collect(toSet());
My suggestion would be to use predicates rather than your Filter classes. They make for cleaner code. I would also suggest making commonly used properties like "name" or "owner" into interfaces that provide predicates for searchability. For instance, for the "name" and "owner" properties you might have two interfaces called "Named" and "Owned":
public interface Named {
public String getName();
public void setName(String name);
static <T extends Named> Predicate<T> nameEquals(Class<T> clazz, String s){
return ((p) -> {
if (s == null){
return p.getName() == null;
}
return s.equals(p.getName());
});
}
}
public interface Owned {
public String getOwner();
public void setOwner(String owner);
public static <T extends Owned> Predicate<T> ownerEquals(Class<T> clazz, String s){
return ((p) -> {
if (s == null){
return p.getOwner() == null;
}
return s.equals(p.getOwner());
});
}
}
Then your Product class implements these interfaces, along with a couple simple convenience methods for calling the interface static methods:
public class Product implements Named, Owned{
private String name;
private String owner;
public String getOwner() {
return owner;
}
public String getName() {
return name;
}
public void setOwner(String owner){
this.owner = owner;
}
public void setName(String name){
this.name = name;
}
public static Predicate<Product> nameEquals(String s){
return Named.nameEquals(Product.class, s);
}
public static Predicate<Product> ownerEquals(String s){
return Owned.ownerEquals(Product.class, s);
}
}
And voila, your Product is searchable. Then your find() method's signature changes to take a predicate:
public interface Finder<T> {
Set<T> find(Predicate p);
}
One of the wonderful things about predicates is how easy they are to combine and compound with one another. For example, let's say we want to find() any products named "cucumber" who aren't owned by "john", or any products owned by "john" with any other names. The call to find() is pretty clean and understandable:
finder.find(
Product.nameEquals("cucumber")
.and(Product.ownerEquals("john").negate())
.or(
Product.ownerEquals("john")
.and(Product.nameEquals("cucumber").negate())
)
);
I should be pretty clear what this block of code is doing. I used the indentation to try and make it clearer how they combine. We can combine the different predicates to our hearts' content.
How to print any class instance in Java? Similar to JSON.stringify() in Javascript. Not necessary JSON, any format of output will do.
public class User {
public String name, password;
public int age;
public ArrayList<String> phones;
public static void login() {
//do something
}
}
User X = new User;
X.name = "john connor";
X.password = "skynet";
X.age = "33";
X.phones.add("1234567");
X.phones.add("7654321");
System.out.println(printClass(X))
Should output something like:
{ name:"john connor", password: "skynet", age: "33", phones:
["1234567", "7654321"], login: void function() }
You can use Apache's commons-lang's ToStringBuilder.reflectionToString
Of course, reflection is slow, so only do this with your test code. for normal use, please use eclipse's "Source" menu -> generate toString() (or intellij's generate toString()) which gives you a decent string.
There could be many ways to achieve what you need. Though i would be interested in why you need.
Override the toString() method.
see: http://www.javapractices.com/topic/TopicAction.do?Id=55
If the generation algorithm gets too long, then consider a separate class say UserPrettyPrinter.
public interface UserPrettyPrinter {
string print(User);
}
public class PrintUserInJSON implements UserPrettyPrinter {
string print(User user) {
//implement the algo here
}
}
you can also implement:
public class PrintUserInXML implements UserPrettyPrinter {
string print(User user) {
//implement the algo here
}
}
Either in conjugation to number-2 or as a standalone class, you can write
public class PrintObjectBasicAlgo {
String print(Object obj) {
/* i write pseudo code here. just ask if you cannot implement this
this would help: http://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html
Class class = Obj.getClass();
Filed[] allVariables = class.getAllFieldsByReflection();
ArrayList<String> keys = new ArrayList<String>;
ArrayList<String> values = new ArrayList<String>;
for(Field field : allVariables) {
Object value = reflectionGetValueOfField( field, obj );
keys.add( field.getName());
values.add(value.toString());
}
now that you have the keys and values, you can generate a string in anyway you like
*/
}
}
You may see Visitor Pattern. it might be helpful.
You have two options here. The simple one is just to override the toString function for your class. I dont see why you dont do this really. In this case its as simple as
String toString(){
return "{ name:\""+name+", password: \""+passowrd....
}
The second option is to use reflection. This would be slightly (though not really) better if you had some sorta external class used for "printing classes". The pseudo code for that would be
StringBuilder s = new StringBuidler();
for(Field f : fields){
s.append(f.getName() + "\" :\"" + f.get()+ "\"");
}
return s.toString();
However this would be costly as reflection always is. Also if you just properly override the toString functions in the first place your printClass function could literally just be
String printClass(Object o){ return o.toString();}
Which of course again begs the question of why do you need a printClass function?
One option is to use Google Gson.
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
class Project {
private int year = 1987;
private String name = "ROBOCOP-1";
private boolean active = false;
private List<String> list = new ArrayList<String>() {
{
add("PROTECT THE INNOCENT");
add("UPHOLD THE LAW");
add("SERVE THE PUBLIC TRUST");
add("CLASSIFIED");
}
};
}
public class GsonExample {
public static void main(String[] args) {
Project obj = new Project();
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println(gson.toJson(obj));
}
}