Type safe property paths using QueryDSL

Property paths are often described as string, which is not type-safe and very error prone. In this blog post I will demonstrate how to replace these string based expressions with type-safe property paths, allowing faulty property paths to be detected at compile time.

Introduction




Paths to bean properties are often described in a string format which is not type-safe and very error prone. Imagine we have the following beans:




public class Car {
private Person owner;
private Integer horsePower;
}

public class Person {
private String name;
}



Then the expression of a car owner would be “owner.name”. Where it is common practice to nest properties with the period ‘.’ character. Many frameworks, such as Spring and Wicket, build on this usage of property expressions, for example:




new Sort("owner.car");



However, the usage of a string based property path is very error prone and faults can be hard to detect. Image that the ‘name’ property gets changed to ‘firstName’, then our sort would no longer work. And because the path is a string, we will not know about this bug until runtime (if there are proper tests)!




Wouldn’t it be nicer to express paths to a bean property entirely type-safe, filtering out invalid property paths at compile time?



QueryDSL




QueryDSL is a framework that can be used to perform type-safe queries. Queries are specified from a type-safe meta model, which can be generated for any type of bean. We could also use this meta model to specify type-safe property paths.


Our generated meta model looks as follows:




public class QCar extends BeanPath<Car> {
public static final QCar car = new QCar(new BeanPath<Car>(Car.class, "car"));
public final QPerson owner = new QPerson(new BeanPath<Person>(Person.class, this, "owner"));
public final NumberPath<Integer> horsePower = createNumber("horsePower", Integer.class);

public QCar(BeanPath<? extends Car> entity) {
super(entity.getType(), entity.getMetadata());
}

public QCar(PathMetadata<?> metadata) {
super(Car.class, metadata);
}
}

public class QPerson extends BeanPath<Person> {
public static final QPerson person = new QPerson(new BeanPath<Person>(Person.class, "person"));
public final StringPath name = createString("name");

public QPerson(BeanPath<? extends Person> entity) {
super(entity.getType(), entity.getMetadata());
}

public QPerson(PathMetadata<?> metadata) {
super(Person.class, metadata);
}
}



So a car owner would be expressed as “QCar.car.owner.name”.




Because the meta model is (re)generated during compilation, it is always kept up to date with our domain beans. Causing faulty paths to be detected at compile time.



Usage




Replacing the string based expression with a type-safe QueryDSL path clearly has many advantages. Below I will demonstrate some examples:



Hamcrest matchers




Car car = new Car().setOwner(new Person("joe"));
assertThat(car, hasValue(QCar.car.owner.name, equalTo("joe")));

Full code snippet here.




Rather than:




assertThat(car, hasProperty("owner", hasProperty("name", equalTo("joe")));



Besides guaranteeing that the property path is valid, we also enforce that the property matcher has to match our property type. Meaning that we can only use string based matchers on the “owner.name” property, where before any type of matcher was allowed.



Sorting




Car car = new Car().setHorsePower(50);
Car betterCar = new Car().setHorsePower(150);
assertEquals(-1, pathComparator(QCar.car.horsePower).compare(car, betterCar));


Full code snippet here.



Clearly the major frameworks, described above, will not let their public API depend on QueryDSL. But it is quite easy to build your own decorator, which translates the property path into a string based expression. That way you can enjoy type safety with little effort.

10 comments:

  1. I will really appreciate the writer's choice for choosing this excellent article appropriate to my matter.Here is deep description about the article matter which helped me more. development loan rates

    ReplyDelete
  2. I use basically superior fabrics : you will discover these products by: repossessed houses

    ReplyDelete
  3. It's all close to home property, even your Rembrandt and your VanGogh, particularly them. appraisers

    ReplyDelete
  4. Our arrival on this venture will be driven by two essential factors: our rental pay and the valuation for the property estimation. The Clavon

    ReplyDelete
  5. Autonomous Valuation: Many land owners will acquire a valuation consistently on the side of their property financing bundle. It isn't abnormal for such valuations to happen every year. Significantly they are finished by a certified and enrolled valuer. https://yes-mallorca-property.com

    ReplyDelete
  6. The type of real estate will also determine your investment strategy, so make sure that you know what kind of property and investment strategy you are looking for to achieve your desired profits. property wealth advisor northern beaches

    ReplyDelete
  7. As we set up these, we may spot things that we haven't yet determined and we may need to return and include them in the proper spots. https://yes-mallorca-property.com/offers/sale/

    ReplyDelete
  8. You should incorporate Voids into your cost structure or overheads. Void Periods, alluded to just as Voids, are the occasions when your level isn't let out yet you should keep on paying the home loan and related costs like Service Charges, on account of a Leasehold property.Calgary Real Estate

    ReplyDelete
  9. I have recently started a blog, the info you provide on this site has helped me greatly. Thanks for all of your time & work immobilienmakler mülheim an der ruhr

    ReplyDelete
  10. It was a wonderful chance to visit this kind of site and I am happy to know. thank you so much for giving us a chance to have this opportunity.. immobilienmakler mülheim

    ReplyDelete