Do we need to register a Custom Validator somewhere?

Tags: #<Tag:0x00007f0f1c3a3ba8>

Hi :smiley_cat: We created a custom Validator for class RadiologyOrder (extends TestOrder) and noticed that the OrderValidator is called via AOP before our method “saveRadiologyOrder” is executed. We would like to call our own custom RadiologyOrderValidator. Do we need to register the Validator somewhere?

You need to have an @Handler(supports = …) annotation, like in this example here:

1 Like

We already have that

@Handler(supports = { RadiologyOrder.class })
public class RadiologyOrderValidator implements Validator {

Is there any other config required?

1 Like

@teleivo are you saying your custom validator isn’t getting called? Because that looks correct

@wyclif yes, the OrderValidator from the core is used instead of our RadiologyOrderValidator

Given the following snippet of code, I’m surprised that only one validator fires:

I suggest using the debugger and stepping through.

Is the validator declared as a bean in Spring application context ?

<bean id="orderValidator" class="org.openmrs.validator.OrderValidator" />
<bean id="drugOrderValidator" class="org.openmrs.validator.DrugOrderValidator" />

Also, can you show us the supports method of RadiologyOrderValidator ?

1 Like

Good point.

(I had thought that @Handler extends @Component, but it does not. So you need to make sure to do @Component, or else declare the bean in XML.)

thanks a lot @lluismf and @darius, defining the bean and correctly setting the @Handler properly made the custom RadiologyOrderValidator being called. Unfortunately as code shows that @darius posted also the OrderValidator is being called as well.

So the problem we have is that we want to create an encounter when saving a RadiologyOrder in RadiologyService.saveRadiologyOrder(RadiologyOrder). Order.encounter has a not null constraint which the OrderValidator enforces. So for us this is too strict, therefore we thought of adding a RadiologyOrderValidator which does not give us an error when RadiologyOrder.encounter is null. Unfortunately the OrderValidator is called as well :frowning: Do you have an idea how we could prevent the call to OrderValidator?

In designing orders, we presumed that they would always occur within a context – i.e., within an order session and/or part of a visit – rather than ad hoc without any context beyond patient & orderer.

We are working to introduce a distinction between technical transactions & clinical/administrative transactions (i.e., a distinction between data that arrive together vs. data that should be meaninfully grouped based on clinical and/or administrative needs). So far, encounter has conflated both of these notions.

You would probably be better off to create an encounter for any radiology order(s) that belong together, since existing API services and other module code will assume there is an encounter for each order (so bypassing the validation will likely cause problems elsewhere). Also, you will not have a way to explicitly link these orders to a visit except through an encounter.

What is the reason that you cannot create an encounter for orders? Perhaps we could find a workaround for that in the near term until the API is more flexibile (allowing technical transactions to be created instead of forcing you to make a clinical encounter) in a future version.

Making RadiologyOrder not an Order is an option ? Using composition (HAS) instead of inheritance (IS-A).

I don’t see any mechanism in getValidators to skip a given validator.

@burke thanks for the explanations!

I am able to create an encounter for the radiology order, I just want to do that within the Radiology API thus in RadiologyService.saveRadiologyOrder(). So that the client code does not have to do that. Therefore I wanted to create a custom RadiologyOrderValidator which does not check if RadiologyOrder.encounter is null, since I am creating one in saveRadiologyOrder().

I guess I have to rename the method saveRadiologyOrder to something that does not start with “save” or “create” to avoid the OrderValidator being called via AOP and then use only the RadiologyOrderValidator. Would you suggest that I use AOP as well to just call the RadiologyOrderValidator before saveRadiologyOrder()? Or is there a non AOP way?

@lluismf, I am more in favor of inheritance in this case, since RadiologyOrder is an Order and it was the intent of the Order Entry API to have TestOrders like lab, rad. But thank you for your suggestion!!

One possible way to solve this: annotate the domain class with the list of validators to exclude from the validation, and modify the validation algorithm to take into account that. Requires changes in core though.

In general, it is bad practice to try and elude validators in core because in most cases the minimum restrictions are intended to enforce DB constraints and preserving data integrity, so you might manage to get past the validator but the saving of the order might still fail if order.encounter is not nullable in the DB.

I basically agree with you, but if a customer needs to create orders without encounter as it seems the case, something must be done.

just to clarify what I am trying to achieve, here is my method

@Transactional
@Override
public RadiologyOrder saveRadiologyOrder(RadiologyOrder radiologyOrder) {
	if (radiologyOrder == null) {
		throw new IllegalArgumentException("radiologyOrder is required");
	}
	
	if (radiologyOrder.getOrderId() != null) {
		throw new IllegalArgumentException("Cannot edit an existing order!");
	}
	
	if (radiologyOrder.getStudy() == null) {
		throw new IllegalArgumentException("radiologyOrder.study is required");
	}
	
	Encounter encounter = saveRadiologyOrderEncounter(radiologyOrder.getPatient(), radiologyOrder.getOrderer(),
	    new Date());
	encounter.addOrder(radiologyOrder);
	
	OrderContext orderContext = new OrderContext();
	orderContext.setCareSetting(RadiologyProperties.getRadiologyCareSetting());
	orderContext.setOrderType(RadiologyProperties.getRadiologyTestOrderType());
	
	RadiologyOrder result = (RadiologyOrder) orderService.saveOrder(radiologyOrder, orderContext);
	saveStudy(result.getStudy());
	return result;
}

I am using the orderService.saveOrder() to save the RadiologyOrder which will causes the OrderValidator to be called and validate the RadiologyOrder anyway. I just dont want it to be called before saveRadiologyOrder, since the encounter is created inside the method and RadiologyOrder.encounter is null at that stage.

I hope its clear now, and not considered bad practice :smile:

It makes perfect sense that custom order types will often need custom validators and that these should be run before the core validators. It seems, from the top of this discussion, that @teleivo is approaching this correctly, but his custom validator is either not being called or is being called after the built-in (order) validator, which is a problem.

@teleivo, any chance you can debug to confirm that your validator is in the list of validators seen by HibernateAdministrationDAO?

@wyclif, @darius, @lluismf, how can we ensure that custom order validators introduced by modules are executed before the API’s validators?

Dear @burke yes my custom validator is called before the OrderValidator. This happens before execution of saveRadiologyOrder. The issue is that the object RadiologyOrder does not contain an encounter at this time. So the order is not an issue. Its that OrderValidator is called at all. I just don’t want that OrderValidator is called so that my method gets executed, I can create an encounter, add it to the radioloyorder and call orderservice.save order where the OrderValidator is welcome :smile:

IIRC validators are handlers and these have an annotation with an order attribute. Not sure if this order is taking into account right now.