Search in sources :

Example 1 with Coercion

use of org.apache.tapestry5.commons.services.Coercion in project tapestry-5 by apache.

the class AbstractBeanModelSourceImplTest method default_model_for_bean.

/**
 * Tests defaults for property names, labels and conduits.
 */
@Test
public void default_model_for_bean() {
    Messages messages = mockMessages();
    stub_contains(messages, false);
    replay();
    BeanModel model = source.create(SimpleBean.class, true, messages);
    assertSame(model.getBeanType(), SimpleBean.class);
    // Based on order of the getter methods (no longer alphabetical)
    assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
    assertEquals(model.toString(), "BeanModel[org.apache.tapestry5.internal.services.SimpleBean properties:firstName, lastName, age]");
    PropertyModel age = model.get("age");
    assertEquals(age.getLabel(), "Age");
    assertSame(age.getPropertyType(), int.class);
    assertEquals(age.getDataType(), "number");
    PropertyModel firstName = model.get("firstName");
    assertEquals(firstName.getLabel(), "First Name");
    assertEquals(firstName.getPropertyType(), String.class);
    assertEquals(firstName.getDataType(), "text");
    assertEquals(model.get("lastName").getLabel(), "Last Name");
    PropertyConduit conduit = model.get("lastName").getConduit();
    SimpleBean instance = new SimpleBean();
    instance.setLastName("Lewis Ship");
    assertEquals(conduit.get(instance), "Lewis Ship");
    conduit.set(instance, "TapestryDude");
    assertEquals(instance.getLastName(), "TapestryDude");
    // Now, one with some type coercion.
    age.getConduit().set(instance, "40");
    assertEquals(instance.getAge(), 40);
    verify();
}
Also used : Messages(org.apache.tapestry5.commons.Messages) BeanModel(org.apache.tapestry5.beanmodel.BeanModel) PropertyModel(org.apache.tapestry5.beanmodel.PropertyModel) PropertyConduit(org.apache.tapestry5.beanmodel.PropertyConduit) Test(org.testng.annotations.Test)

Example 2 with Coercion

use of org.apache.tapestry5.commons.services.Coercion in project tapestry-5 by apache.

the class TypeCoercerImpl method queueIntermediates.

/**
 * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
 * compound coercion tuples
 * to the end of the queue.
 *
 * @param sourceType
 *         the source type of the coercion
 * @param targetType
 *         TODO
 * @param intermediateTuple
 *         a tuple that converts from the source type to some intermediate type (that is not
 *         assignable to the target type)
 * @param consideredTuples
 *         set of tuples that have already been added to the pool (directly, or as a compound
 *         coercion)
 * @param queue
 *         the work queue of tuples
 */
@SuppressWarnings("unchecked")
private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple, Set<CoercionTuple.Key> consideredTuples, LinkedList<CoercionTuple> queue) {
    Class intermediateType = intermediateTuple.getTargetType();
    for (Class c : new InheritanceSearch(intermediateType)) {
        for (CoercionTuple tuple : getTuples(c, targetType)) {
            if (consideredTuples.contains(tuple.getKey())) {
                continue;
            }
            Class newIntermediateType = tuple.getTargetType();
            if (sourceType.isAssignableFrom(newIntermediateType)) {
                continue;
            }
            // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
            // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
            // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
            // intermediate type, hopefully closer to our eventual target type.
            Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
            CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
            // So, every tuple that is added to the queue can take as input the sourceType.
            // The target type may be another intermediate type, or may be something
            // assignable to the target type, which will bring the search to a successful
            // conclusion.
            queue.addLast(compoundTuple);
            consideredTuples.add(tuple.getKey());
        }
    }
}
Also used : CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) InheritanceSearch(org.apache.tapestry5.commons.internal.util.InheritanceSearch) StringToEnumCoercion(org.apache.tapestry5.commons.util.StringToEnumCoercion) Coercion(org.apache.tapestry5.commons.services.Coercion)

Example 3 with Coercion

use of org.apache.tapestry5.commons.services.Coercion in project tapestry-5 by apache.

the class TypeCoercerImpl method findOrCreateCoercion.

/**
 * Here's the real meat; we do a search of the space to find coercions, or a system of
 * coercions, that accomplish
 * the desired coercion.
 *
 * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
 * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
 * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
 *
 * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
 * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
 * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
 * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
 * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
 * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
 * final response.
 *
 * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
 * really good at.
 *
 * @param sourceType
 * @param targetType
 * @return coercer from sourceType to targetType
 */
@SuppressWarnings("unchecked")
private Coercion findOrCreateCoercion(Class sourceType, Class targetType) {
    if (sourceType == Void.class) {
        return searchForNullCoercion(targetType);
    }
    // Trying to find exact match.
    Optional<CoercionTuple> maybeTuple = getTuples(sourceType, targetType).stream().filter((t) -> sourceType.equals(t.getSourceType()) && targetType.equals(t.getTargetType())).findFirst();
    if (maybeTuple.isPresent()) {
        return maybeTuple.get().getCoercion();
    }
    // These are instance variables because this method may be called concurrently.
    // On a true race, we may go to the work of seeking out and/or fabricating
    // a tuple twice, but it's more likely that different threads are looking
    // for different source/target coercions.
    Set<CoercionTuple.Key> consideredTuples = CollectionFactory.newSet();
    LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
    seedQueue(sourceType, targetType, consideredTuples, queue);
    while (!queue.isEmpty()) {
        CoercionTuple tuple = queue.removeFirst();
        // If the tuple results in a value type that is assignable to the desired target type,
        // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
        // "quality" (how close is the tuple target type to the desired target type). Cost
        // is currently implicit, as compound tuples are stored deeper in the queue,
        // so simpler coercions will be located earlier.
        Class tupleTargetType = tuple.getTargetType();
        if (targetType.isAssignableFrom(tupleTargetType)) {
            return tuple.getCoercion();
        }
        // So .. this tuple doesn't get us directly to the target type.
        // However, it *may* get us part of the way. Each of these
        // represents a coercion from the source type to an intermediate type.
        // Now we're going to look for conversions from the intermediate type
        // to some other type.
        queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
    }
    throw new CoercionNotFoundException(String.format("Could not find a coercion from type %s to type %s.", sourceType.getName(), targetType.getName()), buildCoercionCatalog(), sourceType, targetType);
}
Also used : PlasticUtils(org.apache.tapestry5.plastic.PlasticUtils) TypeCoercer(org.apache.tapestry5.commons.services.TypeCoercer) InternalCommonsUtils(org.apache.tapestry5.commons.internal.util.InternalCommonsUtils) Collection(java.util.Collection) Set(java.util.Set) StringToEnumCoercion(org.apache.tapestry5.commons.util.StringToEnumCoercion) LockSupport(org.apache.tapestry5.commons.internal.util.LockSupport) List(java.util.List) F(org.apache.tapestry5.func.F) Coercion(org.apache.tapestry5.commons.services.Coercion) CoercionNotFoundException(org.apache.tapestry5.commons.util.CoercionNotFoundException) CollectionFactory(org.apache.tapestry5.commons.util.CollectionFactory) Map(java.util.Map) CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) AvailableValues(org.apache.tapestry5.commons.util.AvailableValues) Optional(java.util.Optional) InheritanceSearch(org.apache.tapestry5.commons.internal.util.InheritanceSearch) LinkedList(java.util.LinkedList) Collections(java.util.Collections) WeakHashMap(java.util.WeakHashMap) CoercionFailedException(org.apache.tapestry5.commons.util.CoercionFailedException) UnknownValueException(org.apache.tapestry5.commons.util.UnknownValueException) CoercionNotFoundException(org.apache.tapestry5.commons.util.CoercionNotFoundException) CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple)

Example 4 with Coercion

use of org.apache.tapestry5.commons.services.Coercion in project tapestry-5 by apache.

the class SelectTest method submitted_option_matches_against_value_encoded_option_model_value.

/**
 * This a test for TAP5-2184
 */
@Test
public void submitted_option_matches_against_value_encoded_option_model_value() throws ValidationException {
    ValueEncoder<Integer> encoder = getService(ValueEncoderSource.class).getValueEncoder(Integer.class);
    ValidationTracker tracker = mockValidationTracker();
    Request request = mockRequest();
    Messages messages = mockMessages();
    FieldValidationSupport fvs = mockFieldValidationSupport();
    TypeCoercer typeCoercer = mockTypeCoercer();
    InternalComponentResources resources = mockInternalComponentResources();
    Binding selectModelBinding = mockBinding();
    expect(request.getParameter("xyz")).andReturn("5");
    expect(messages.contains(EasyMock.anyObject(String.class))).andReturn(false).anyTimes();
    expect(resources.getBinding("model")).andReturn(selectModelBinding);
    final Holder<SelectModel> modelHolder = Holder.create();
    expect(typeCoercer.coerce(EasyMock.or(EasyMock.isA(SelectModel.class), EasyMock.isNull()), EasyMock.eq(SelectModel.class))).andAnswer(new IAnswer<SelectModel>() {

        @Override
        public SelectModel answer() throws Throwable {
            return modelHolder.get();
        }
    });
    expect(selectModelBinding.get()).andAnswer(new IAnswer<SelectModel>() {

        @Override
        public SelectModel answer() throws Throwable {
            return modelHolder.get();
        }
    });
    Select select = new Select();
    tracker.recordInput(select, "5");
    fvs.validate(5, resources, null);
    replay();
    // TAP5-2184 is triggered by the automatic String->SelectModel coercion, because the OptionModel
    // values are Strings even if the desired property type is not (Integer, here). Select has a little
    // hack to run the model values through the ValueEncoder for comparison.
    modelHolder.put(getService(TypeCoercer.class).coerce("1,5,10,20", SelectModel.class));
    set(select, "encoder", encoder);
    set(select, "model", modelHolder.get());
    set(select, "request", request);
    set(select, "secure", SecureOption.ALWAYS);
    // Disable BeanValidationContextSupport
    set(select, "beanValidationDisabled", true);
    set(select, "tracker", tracker);
    set(select, "fieldValidationSupport", fvs);
    set(select, "typeCoercer", typeCoercer);
    set(select, "resources", resources);
    select.processSubmission("xyz");
    verify();
    assertEquals(get(select, "value"), 5);
}
Also used : Messages(org.apache.tapestry5.commons.Messages) InternalComponentResources(org.apache.tapestry5.internal.InternalComponentResources) TypeCoercer(org.apache.tapestry5.commons.services.TypeCoercer) Request(org.apache.tapestry5.http.services.Request) ValueEncoderSource(org.apache.tapestry5.services.ValueEncoderSource) EnumSelectModel(org.apache.tapestry5.util.EnumSelectModel) Test(org.testng.annotations.Test)

Example 5 with Coercion

use of org.apache.tapestry5.commons.services.Coercion in project tapestry-5 by apache.

the class EnumValueEncoderTest method roundtrip_with_custom_coercer.

@Test
public // TAP5-2496
void roundtrip_with_custom_coercer() {
    CoercionTuple<Stooge, String> stoogeToString = CoercionTuple.create(Stooge.class, String.class, new Coercion<Stooge, String>() {

        @Override
        public String coerce(Stooge input) {
            return String.valueOf(input.ordinal());
        }
    });
    CoercionTuple<String, Stooge> stringToStooge = CoercionTuple.create(String.class, Stooge.class, new Coercion<String, Stooge>() {

        @Override
        public Stooge coerce(String input) {
            return Stooge.values()[Integer.parseInt(input)];
        }
    });
    Map<CoercionTuple.Key, CoercionTuple> map = new HashMap<>();
    map.put(stoogeToString.getKey(), stoogeToString);
    map.put(stringToStooge.getKey(), stringToStooge);
    TypeCoercer typeCoercer = new TypeCoercerImpl(map);
    EnumValueEncoder<Stooge> encoder = new EnumValueEncoder<Stooge>(typeCoercer, Stooge.class);
    Stooge serverValue = Stooge.LARRY;
    String clientValue = encoder.toClient(serverValue);
    Stooge convertedBack = encoder.toValue(clientValue);
    assertEquals(convertedBack, serverValue);
}
Also used : HashMap(java.util.HashMap) TypeCoercer(org.apache.tapestry5.commons.services.TypeCoercer) CoercionTuple(org.apache.tapestry5.commons.services.CoercionTuple) TypeCoercerImpl(org.apache.tapestry5.commons.internal.services.TypeCoercerImpl) Test(org.testng.annotations.Test)

Aggregations

CoercionTuple (org.apache.tapestry5.commons.services.CoercionTuple)4 Collection (java.util.Collection)3 List (java.util.List)3 Messages (org.apache.tapestry5.commons.Messages)3 Coercion (org.apache.tapestry5.commons.services.Coercion)3 TypeCoercer (org.apache.tapestry5.commons.services.TypeCoercer)3 StringToEnumCoercion (org.apache.tapestry5.commons.util.StringToEnumCoercion)3 Test (org.testng.annotations.Test)3 Map (java.util.Map)2 BeanModel (org.apache.tapestry5.beanmodel.BeanModel)2 PropertyConduit (org.apache.tapestry5.beanmodel.PropertyConduit)2 PropertyModel (org.apache.tapestry5.beanmodel.PropertyModel)2 InheritanceSearch (org.apache.tapestry5.commons.internal.util.InheritanceSearch)2 RenderCommand (org.apache.tapestry5.runtime.RenderCommand)2 ValueEncoderFactory (org.apache.tapestry5.services.ValueEncoderFactory)2 ReadPreference (com.mongodb.ReadPreference)1 WriteConcern (com.mongodb.WriteConcern)1 File (java.io.File)1 BigDecimal (java.math.BigDecimal)1 BigInteger (java.math.BigInteger)1