### Question:
Property extends BaseProperty<E> implements ComparableProperty<E>, RelationshipProperty<E> { public Property<String> concat(Object... args) { Expression[] exp = new Expression[args.length + 1]; int i = 0; exp[i++] = path(); for(Object arg : args) { if(arg instanceof org.apache.cayenne.exp.property.Property) { exp[i++] = ((org.apache.cayenne.exp.property.Property<?>) arg).getExpression(); } else if(arg instanceof Expression) { exp[i++] = (Expression) arg; } else if(arg != null) { exp[i++] = ExpressionFactory.wrapScalarValue(arg.toString()); } } return create(FunctionExpressionFactory.concatExp(exp), String.class); } protected  Property(final String name, final Class<E> type); protected  Property(final String name, final Expression expression, final Class<E> type); Expression like(String pattern); Expression like(String pattern, char escapeChar); Expression likeIgnoreCase(String pattern); Expression nlike(String value); Expression nlikeIgnoreCase(String value); Expression contains(String substring); Expression startsWith(String value); Expression endsWith(String value); Expression containsIgnoreCase(String value); Expression startsWithIgnoreCase(String value); Expression endsWithIgnoreCase(String value); Property<Integer> length(); Property<Integer> locate(String string); Property<Integer> locate(Property<? extends String> property); Property<String> trim(); Property<String> upper(); Property<String> lower(); Property<String> concat(Object... args); Property<String> substring(int offset, int length); Property<E> avg(); Property<E> sum(); Property<E> mod(Number number); Property<E> abs(); Property<E> sqrt(); Property<T> flat(Class<T> tClass); @Override Property<E> alias(String alias); @Override Property<E> outer(); Property<T> dot(Property<T> property); @Override Property<Object> dot(String property); @Override Property<E> max(); @Override Property<E> min(); @SuppressWarnings("unchecked") static Property<T> create(String name, Class<? super T> type); @SuppressWarnings("unchecked") static Property<T> create(Expression expression, Class<? super T> type); @SuppressWarnings("unchecked") static Property<T> create(String name, Expression expression, Class<? super T> type); @SuppressWarnings("unchecked") static Property<T> createSelf(Class<? super T> type); @Deprecated
    static final Property<Long> COUNT; }### Answer:
@Test public void testConcat() { Property<String> p = Property.create("test", String.class); Property<String> p2 = Property.create("concat", String.class); Expression exp = new ASTScalar(3); Property<String> newProp = p.concat("string", exp, p2); assertTrue(newProp.getExpression() instanceof ASTConcat); assertEquals(p.getExpression(), newProp.getExpression().getOperand(0)); assertEquals("string", newProp.getExpression().getOperand(1)); assertEquals(3, newProp.getExpression().getOperand(2)); assertEquals(p2.getExpression(), newProp.getExpression().getOperand(3)); }