There's a bean validation in a project's jar which validation.xml contains field-level validation of Address bean.
The other project uses Address class and needs to have specific Address validation. So extended-validation.xml was created with class-level validation of Address bean.
As a result, during the app deployment, ValidationException occures: javax.validation.ValidationException: my.base.datatypes.Address has already be configured in xml..
Here are two validation xml files with basic validation and "extended validation".
validation.xml
<bean class="my.base.datatypes.Address" ignore-annotations="true">
<getter name="country">
<constraint annotation="my.imp.services.validation.ValidCode">
<message>{msg01}</message>
<groups>
<value>my.imp.services.validation.ImportGroup</value>
</groups>
<element name="name">Country</element>
</constraint>
</getter>
</bean>
extended-validation.xml
<bean class="my.base.datatypes.Address" ignore-annotations="true">
<class ignore-annotations="true">
<constraint annotation="my.extended.imp.services.validation.ValidAddress">
<message>ERROR DURING ADDRESS VALIDATION</message>
<groups>
<value>my.imp.services.validation.ImportGroup</value>
</groups>
</constraint>
</class>
</bean>
Is it possible to extend already existing validation?
The solution appears to be very simple and trivial. If you want to extend validation rules, use different validator which will load extended-validation.xml constraints configuration. In this case, base validator validates data according to validation.xml config, and another validator validates data according to extended-validation.xml config. So no more config collisions occur.
Related
I am implementing a multitenant application with the spring security saml extention.
I have a Service Provider (SP) for each tenant.
All SPs runs on the same server exposed with SP-specific 2nd level domain:
sp1.myapp.com/myapi/1/
sp1.myapp.com/myapi/2/
In each SP metadata file I have configured the tenant-specific AssertionConsumerService.
When I test the SSO Login, I get a KO on SP side when it gets the response of the Identity Provider (IDP).
On Log side i see only:
ERROR [BaseSAMLMessageDecoder] SAML message intended destination endpoint 'https://sp1.myapp.com/myapi/saml/SSO' did not match the recipient endpoint 'https://default.myapp.com/myapi/saml/SSO'
Where the 'https://default.myapp.com/myapi/saml/SSO' is the URL set as serverName of the load balancer context provider:
<bean id="lbContextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB" init-method="afterPropertiesSet">
<property name="metadata" ref="metadata" />
<property name="keyManager" ref="keyManager" />
<property name="scheme" value="https" />
<property name="serverName" value="default.myapp.com" />
<property name="contextPath" value="/myapi" />
<property name="serverPort" value="443" />
<property name="includeServerPortInRequestURL" value="true" />
</bean>
Question
In the docs.spring.io/spring-security-saml I see that
Service provider can now define multiple assertion consumer endpoints with same binding
How can I configure it?
Does it conflict with load balancer context provider?
Can I provide multiple AssertionConsumerService with different 2nd level domains without reproduction this conflict?
I already tested:
This question seems to be fixed with the LB, but anyone knows if I can provide multiple serverName to load balancer context provider (maybe with a dynamic pick)?
Disable the checking of the InResponseToField as suggested at ch.13 docs.spring.io/spring-security-saml and for this and this question.
Configure the defaultTargetUrl of the successRedirectHandler (where I am using a custom superclass of org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler) as suggested for this question. In addition this solution is not multitenant.
<bean id="successRedirectHandler" class="org.MySamlAuthenticationSuccessHandler"
init-method="afterPropertiesSet">
<property name="contextPath" value="/myapi" />
<property name="defaultTargetUrl" value="https://default.myapp.com/myapi/saml/SSO"/>
<property name="requireProxyWrapping" value="false"/>
</bean>
Customize SAMLContextProviderLB by extending SamlContextProviderLB.
In custom class, add constructor and initialize with default values.
Override getLocalAndPeerEntity/getLocalEntity/populateLocalEntityId. In each of this method set lbDomain based on domain in requestURL.
above approach worked for me.
I am trying to do the following using spring integration.
I would like to read from an input channel an incoming Message that goes throws a series of Steps and produces a final message.Each step can throw an Exception. This could be either due to a DB call or ExternalCall etc. Each step is considered as a service-activator. If all is well a successful a final Message is generated.I need to handle each Exception thrown by each Step as a separate case and then produce the appropriate final Message.
Using the below xml I have written a test code that passes when sucessfull but when an error occurs although I see a Final message generated in the postSend (sent=true) on channel 'bean 'finalChannel' log but the process does not return to the final queue.
Why does this happen?
<?xml version="1.0" encoding="UTF-8"?>
<context:component-scan base-package="com.demo.">
</context:component-scan>
<header-enricher input-channel="inputChannel"
output-channel="enrichedChannel">
<header name="initialMessage" expression="getPayload()" />
</header-enricher>
<!-- first-step -->
<service-activator input-channel="enrichedChannel"
output-channel="firstStep" ref="validateOne" />
<gateway id="validateOne" default-request-channel="ch1"
error-channel="errors1" />
<chain input-channel="ch1">
<service-activator id="mockServiceOneActivator"
ref="mockServiceOne" method="register" />
</chain>
<!-- enrich-header with payload to be available down the line -->
<header-enricher input-channel="firstStep"
output-channel="secondStep">
<header name="initialInfo" expression="getPayload()" />
</header-enricher>
<!-- second-step -->
<service-activator input-channel="secondStep"
output-channel="enrichWithTwoChannel" ref="validateTwo" />
<gateway id="validateTwo" default-request-channel="ch2"
error-channel="errors2" />
<chain input-channel="ch2">
<service-activator id="mockServiceTwoActivator"
ref="mockServiceTwo" method="callExternal" />
</chain>
<!-- enrich-header with payload to be available down the line -->
<header-enricher input-channel="enrichWithTwoChannel"
output-channel="eligibilityCheck">
<header name="serviceTwoInfo" expression="getPayload()" />
</header-enricher>
<!-- final-step -->
<service-activator input-channel="eligibilityCheck"
output-channel="finalChannel" id="mockServiceFinalActivator"
ref="mockServiceFinal" method="submit" />
<!-- error handling -->
<service-activator input-channel="errors1"
output-channel="finalChannel" ref="traceErrorHandler"
method="handleFailedTrace" />
<service-activator input-channel="errors2"
output-channel="finalChannel" ref="traceErrorHandler2"
method="handleFailedTrace" />
<channel id="finalChannel">
<queue />
</channel>
<service-activator input-channel="errorChannel"
ref="globalExceptionHandler" method="handleError" />
My handler code looks like this ..
#Component("traceErrorHandler")public class TraceErrorHandler {
public Message<FinalMessage> handleFailedTrace(Message<?> errorMessage) {
MessagingException payload = (MessagingException) errorMessage.getPayload();
InitialMessage im = (InitialMessage) payload.getFailedMessage().getHeaders().get("initialMessage");
ServiceOneException error = (ServiceOneException) payload.getCause();
FinalMessage v = new FinalMessage(im.getFrom(), im.getTo(), error.getErrorTemplate());
Message<FinalMessage> finalMessage = MessageBuilder.withPayload(v).copyHeaders(payload.getFailedMessage().getHeaders()).build();
return finalMessage;
}}
I am not sure if this is the correct approach in regards to error-handling. The initial chains are simple activators but further down the line there will be more logic.
Should we I always use chains to handle separate error channels
Even if its a single activator service called.
Only when there are Multiple service-activator/transforms that encapsulate a single point of error?
EDIT 1
I added a request-handler-advice-chain reference a bean.
<int:service-activator
id="serviceOneActivator" input-channel="enrichedChannel"
ref="serviceOne" method="register" output-channel="firstStep">
<int:request-handler-advice-chain>
<ref bean="myclass" />
</int:request-handler-advice-chain></int:service-activator>
The reference bean is at first a default definition in xml
<bean id="myclass"
class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="failureChannel" ref="finalChannel" />
<property name="onFailureExpression" value="#payload"/>
<property name="returnFailureExpressionResult" value="true" />
</bean>
if I add the <property name="onFailureExpression" value="#payload"/> property it fails with:
Cannot convert value of type 'java.lang.String' to required type 'org.springframework.expression.Expression' for property 'onFailureExpression'
What i would like to do is convert the exception message to a final message object? but all expression i have added seem to fail on load.
A chain with one component makes no sense.
A chain is syntactic sugar only, each component still stands alone at runtime.
If you want to handle errors for individual endpoints, consider using ExpressionEvaluatingRequestHandlerAdvices instead.
See https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/messaging-endpoints.html#message-handler-advice-chain
I am having xml. (Ehcache.xml)
I want to inject into it property from property file(on the classpath).
However since this xml is not a Spring managed bean I am not able to do so.
Any recommendations how to overcome this?
the xml:
...
properties="peerDiscovery=manual,rmiUrls=//**${other.node.hostname}**:41001/org.jasig.cas.ticket.ServiceTicket|//**${other.node.hostname}**:41001/org.jasig.cas.ticket.TicketGrantingTicket"
propertySeparator="," />
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=41001,socketTimeoutMillis=5000" />
</ehcache>
I want to inject ${other.node.hostname} from another properties file.
but I get this on runtime:
Caused by: java.net.URISyntaxException: Illegal character in authority at index 2: //${other.node.hostname}:41001/org.jasig.cas.ticket.TicketGrantingTicket
thanks,
ray.
in the ehcache.xml it won't work because it's not spring configuration. But if you define the equivalent configuration in spring instead of the ehcache file it should work:
<context:property-placeholder location="classpath:config.properties"/>
<bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="maxElementsInMemory" value="${cache.maxMemoryElements}"/>
</bean>
the best is to use the ehcache.xml file the least possible and configure everything in spring, as most of the options in the file have a spring equivalent.
I was looking over this post of using JSR-303 to validate a collection of objects. The solution works great with annotations, but I can't seem to get it to work with the Hibernate Validator XML formatted configuration.
For example, I have code similar to this:
public class DataSet
{
Collection<Data> dataCollection;
public Collection<Data> getDataCollection() {...}
}
From there, I have a custom validator/annotation DataValidator/#ValidData.
In XML, I do this first:
<bean class="DataSet"
ignore-annotations="true">
<field name="dataCollection">
<valid/>
<constraint annotation="ValidData"/>
</field>
</bean>
However, I get the following exception:
Exception in thread "main" javax.validation.UnexpectedTypeException: No validator could be found for type: java.util.Collection<DataSet>
So I swap the <valid> tag with the <constraint> one in the XML. It seems this is not valid with the XSD schema and the XML can no longer be parsed.
<bean class="DataSet"
ignore-annotations="true">
<field name="dataCollection">
<constraint annotation="ValidData"/>
<valid/>
</field>
</bean>
Exception in thread "main" javax.validation.ValidationException: Error parsing mapping file.
Does anyone know how I can use XML to validate this collection with must custom validator?
The key was adding a class-level constraint annotation in the XML to the Data POJO itself.
<bean class="DataSet"
ignore-annotations="true">
<field name="dataCollection">
<valid/>
</field>
</bean>
<bean class="Data" ignore-annotations="true">
<class>
<constraint annotation="ValidData"/>
</class>
</bean>
I am trying to use an external objects in my report.
I added the jar file with external objects to iReport classpath (in settings)
The static text (with I18n)
msg($R{pdf.invoice.finalTitle}, $P{invoice.number})
I have added such definitions into xml:
<import value="crm.object.objects.Invoice"/>
<parameter name="invoice" class="crm.object.objects.Invoice" isForPrompting="false">
<property name="number" value=""/>
<defaultValueExpression><![CDATA[]]></defaultValueExpression>
</parameter>
...
But still it fails during compilation with error: net.sf.jasperreports.engine.design.JRValidationException: Report design not valid : 1. Parameter not found : invoice.number
What I am doing wrong?
Thank you
The parameter you have defined is "invoice", not "invoice.number". So, it should be $P{invoice}. You can then access it's variable, if it has enough access privileges...or by it's getter, as $P{invoice}.getNumber()