Setting various types of properties on a JCR node This code checks value's type and cast it into appropriate type, then puts it into a javax.jcr.Node.

The checking looks long and boring. Is there a way to refactor it?  I'm using Java 7.

/**
 * Set node's property.
 */
public static void setProperty(Node node, String propertyName, Object propertyValue) throws RepositoryException {
    if (node == null) {
        throw new IllegalArgumentException("Something wrong");
    }
    if (propertyName == null) {
        throw new IllegalArgumentException("Property name is invalid");
    }

    if (propertyValue == null) {
        node.setProperty(propertyName, (Value) null);
    } else if (propertyValue instanceof Value) {
        node.setProperty(propertyName, (Value) propertyValue);
    } else if (propertyValue instanceof Node) {
        node.setProperty(propertyName, (Node) propertyValue);
    } else if (propertyValue instanceof Binary) {
        node.setProperty(propertyName, (Binary) propertyValue);
    } else if (propertyValue instanceof Calendar) {
        node.setProperty(propertyName, (Calendar) propertyValue);
    } else if (propertyValue instanceof Date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime((Date) propertyValue);
        node.setProperty(propertyName, cal);
    } else if (propertyValue instanceof BigDecimal) {
        node.setProperty(propertyName, (BigDecimal) propertyValue);
    } else if (propertyValue instanceof String) {
        node.setProperty(propertyName, (String) propertyValue);
    } else if (propertyValue instanceof Long) {
        node.setProperty(propertyName, ((Long) propertyValue).longValue());
    } else if (propertyValue instanceof Double) {
        node.setProperty(propertyName, (Double) propertyValue);
    } else if (propertyValue instanceof Boolean) {
        node.setProperty(propertyName, (Boolean) propertyValue);
    } else if (propertyValue instanceof InputStream) {
        node.setProperty(propertyName, inputStreamToBinary((InputStream) propertyValue));
    } else if (propertyValue instanceof Collection) {
        CollectionFactory factory = CollectionFactoryImpl.getInstance();
        ArrayList&lt;Value&gt; values = new ArrayList&lt;Value&gt;();
        for (Object value : (Collection&lt;Object&gt;) propertyValue) {
            values.add(createValue(value, factory));
        }
        node.setProperty(propertyName, values.toArray(new Value[values.size()]));
    } else {
        throw new IllegalArgumentException("Something wrong");
    }
}


@Test
public void test() {
    Node node = createNode("test");
    setProperty(node, "name", "name");
}
My idea would be to encapsulate the job of casting and converting into some kind of a Strategy pattern.

I would use an enum for that, namely NodeSettingStrategy:

public static enum NodeSettingValueStrategy {
    UNKNOWN(null) {
        @Override
        public void set(Node node, String propertyName, Object value) {
            throw new IllegalArgumentException("Cannot set property to a value of type " + value.getClass());
        }
    },

    DATE(Date.class) {
        @Override
        public void set(Node node, String propertyName, Object value) {
            node.setProperty(propertyName, (Long) value);
        }

    },

    LONG_PRIMITIVE(long.class) {
        @Override
        public void set(Node node, String propertyName, Object value) {
            node.setProperty(propertyName, (long) value);
        }
    },

    LONG(Long.class) {
        @Override
        public void set(Node node, String propertyName, Object value) {
            node.setProperty(propertyName, (Long) value);
        }
    },

    STRING(String.class) {
        @Override
        public void set(Node node, String propertyName, Object value) {
            node.setProperty(propertyName, (String) value);
        }
    },

    NODE(Node.class) {
        @Override
        public void set(Node node, String propertyName, Object value) {
            node.setProperty(propertyName, (Node) value);
        }
    };

    private final Class&lt;?&gt; supportedType;

    private NodeSettingValueStrategy(Class&lt;?&gt; supportedType) {
        this.supportedType = supportedType;
    }

    public static NodeSettingValueStrategy of(Class&lt;?&gt; type) {
        for (NodeSettingValueStrategy strategy : NodeSettingValueStrategy.values()) {
            if (strategy.supportedType == type) {
                return strategy;
            }

        }
        return NodeSettingValueStrategy.UNKNOWN;
    }

    public abstract void set(Node node, String propertyName, Object value);
}


Then I want to hide this NodeSettingStrategy by a thin abstraction, namely NodeSetter:

public static class NodeValueSetter {
    private final NodeSettingValueStrategy strategy;
    private final String propertyName;
    private final Object value;

    private NodeValueSetter(NodeSettingValueStrategy strategy, String propertyName, Object value) {
        this.strategy = strategy;
        this.propertyName = propertyName;
        this.value = value;
    }

    public void setTo(Node node) {
        strategy.set(node, propertyName, value);
    }

    public static NodeValueSetter of(final String propertyName, final Object value) {
        NodeSettingValueStrategy settingStrategy = NodeSettingValueStrategy.of(value.getClass());
        return new NodeValueSetter(settingStrategy, propertyName, value);
    }

}


Combine them together:

@Test
public void should_able_to_set_property() throws Exception {
        Node node = new Node();

        Node givenNode = new Node();
        String someString = "The brown fox jumps over a lazy dog";
        long givenLong = 234234234234L;

        for (NodeValueSetter setter : Arrays.asList(
                NodeValueSetter.of("a-string", someString),
                NodeValueSetter.of("a-number", givenLong),
                NodeValueSetter.of("a-node", givenNode))) {
            setter.setTo(node);
        }

        assertThat(node.getProperty("a-string"), is(someString));
        assertThat(node.getProperty("a-number"), is(givenLong));
        assertThat(node.getProperty("a-node"), is(givenNode));
    }