sorting and null in the path

From: Marcin Skladaniec (marci..sh.com.au)
Date: Wed Nov 07 2007 - 17:16:52 EST

  • Next message: Kevin Menard: "Re: sorting and null in the path"

    Hi
    Quite some time ago I mentioned that sorting using Ordering fails when
    there is a "null in the path". In the past we have made some
    workarounds (mostly not allowing user to sort on certain properties),
    but now we have to move forward. I put together a simple patch which
    does not affect the way cayenne works, but just adds extra
    functionality.

    Ordering has now an additional field "allowNullsInThePath". When this
    field is set to true in the case of "null in the path" exception null
    is returned altogether, but the execution of the sort is not terminated.

    I know that this patch is simplistic^2. I'm open to any suggestions on
    how to actually make it good. We do really need this functionality.

    Marcin
    PS: the patch:

    Index: framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/ObjPathResolvingException.java
    ===================================================================
    --- framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/ObjPathResolvingException.java (revision 0)
    +++ framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/ObjPathResolvingException.java (revision 0)
    ..-0,0 +1,56 @@
    +/*****************************************************************
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements. See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership. The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License. You may obtain a copy of the License at
    + *
    + * http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied. See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + ****************************************************************/
    +package org.apache.cayenne;
    +
    +/**
    + * A runtime exception thrown when <code>PropertyUtils.getProperty()</
    code> finds that there
    + * is a null value in the resolved path.
    + *
    + *..uthor Marcin Skladaniec
    + */
    +public class ObjPathResolvingException extends
    CayenneRuntimeException {
    +
    + /**
    + * Creates new FaultFailureException without detail message.
    + */
    + public ObjPathResolvingException() {
    + super();
    + }
    +
    + /**
    + * Constructs an FaultFailureException with the specified detail
    message.
    + *
    + *..aram msg the detail message.
    + */
    + public ObjPathResolvingException(String msg) {
    + super(msg);
    + }
    +
    + /**
    + * Constructs an FaultFailureException that wraps a
    <code>Throwable</code> thrown
    + * elsewhere.
    + */
    + public ObjPathResolvingException(Throwable th) {
    + super(th);
    + }
    +
    + public ObjPathResolvingException(String msg, Throwable th) {
    + super(msg, th);
    + }
    +}
    Index: framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/query/Ordering.java
    ===================================================================
    --- framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/query/Ordering.java (revision 592920)
    +++ framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/query/Ordering.java (working copy)
    ..-28,6 +28,7 @@

      import org.apache.commons.collections.ComparatorUtils;
      import org.apache.cayenne.exp.Expression;
    +import org.apache.cayenne.exp.ExpressionException;
      import org.apache.cayenne.util.ConversionUtil;
      import org.apache.cayenne.util.Util;
      import org.apache.cayenne.util.XMLEncoder;
    ..-58,6 +59,7 @@
          protected transient Expression sortSpec;
          protected boolean ascending;
          protected boolean caseInsensitive;
    + protected boolean allowNullsInThePath;

          /**
           * Orders a given list of objects, using a List of Orderings
    applied according the
    ..-103,6 +105,15 @@
                  this.sortSpec = null;
              }
          }
    +
    +
    + public void setAllowNullsInThePath(boolean allowNullsInThePath) {
    + this.allowNullsInThePath = allowNullsInThePath;
    + }
    +
    + public boolean getAllowNullsInThePath() {
    + return allowNullsInThePath;
    + }

          /**
           * Returns sortSpec string representation.
    ..-173,8 +184,29 @@
           */
          public int compare(Object o1, Object o2) {
              Expression exp = getSortSpec();
    - Object value1 = exp.evaluate(o1);
    - Object value2 = exp.evaluate(o2);
    + Object value1 = null;
    + Object value2 = null;
    + try {
    + value1 = exp.evaluate(o1);
    + } catch (ExpressionException e) {
    + if (allowNullsInThePath && e.getCause() != null && e.getCause()
    instanceof org.apache.cayenne.ObjPathResolvingException) {
    + //do nothing, we expect this
    + } else {
    + //rethrow
    + throw e;
    + }
    + }
    +
    + try {
    + value2 = exp.evaluate(o2);
    + } catch (ExpressionException e) {
    + if (allowNullsInThePath && e.getCause() != null && e.getCause()
    instanceof org.apache.cayenne.ObjPathResolvingException) {
    + //do nothing, we expect this
    + } else {
    + //rethrow
    + throw e;
    + }
    + }

              // nulls first policy... maybe make this configurable as
    some DB do
              if (value1 == null) {
    Index: framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/reflect/PropertyUtils.java
    ===================================================================
    --- framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/reflect/PropertyUtils.java (revision 592920)
    +++ framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/
    cayenne/reflect/PropertyUtils.java (working copy)
    ..-29,6 +29,7 @@
      import java.util.StringTokenizer;

      import org.apache.cayenne.CayenneRuntimeException;
    +import org.apache.cayenne.ObjPathResolvingException;
      import org.apache.cayenne.map.Entity;
      import org.apache.cayenne.util.Util;

    ..-72,8 +73,7 @@

                      if (value == null) {
                          // null value in the middle....
    - throw new CayenneRuntimeException(
    - "Null value in the middle of the path");
    + throw new ObjPathResolvingException("Null value
    in the middle of the path, failed on"+nestedPropertyName +" from
    "+object);
                      }

                      value = getSimpleProperty(value, pathSegment);

      




    This archive was generated by hypermail 2.0.0 : Wed Nov 07 2007 - 17:17:27 EST