In my Spring Boot project when using the following validation rules in my DTO
#Length(max = 70)
#UnwrapValidatedValue
private Optional<String> vendorName;
I am getting the following exception
javax.validation.ValidationException: HV000182: No validation value unwrapper is registered for type java.util.Optional<java.lang.String>
I can't just find anywhere how to register custom validation value unwrapper in Spring
You should register a ValidatedValueUnwrapper to the validator.
The validator could be configured via the LocalValidatorFactoryBean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<bean name="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationPropertyMap">
<util:map>
<entry key="hibernate.validator.validated_value_handlers"
value="com.mycompany.validator.OptionalValidatedValueUnwrapper"/>
</util:map>
</property>
</bean>
</beans>
or in java:
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.getValidationPropertyMap().put("hibernate.validator.validated_value_handlers",
"com.mycompany.validator.OptionalValidatedValueUnwrapper");
return validator;
}
You could find a proper ValidatedValueUnwrapper implementation in the dropwizard framework (based on the Optional from guava).
public class OptionalValidatedValueUnwrapper extends ValidatedValueUnwrapper<Optional<?>> {
private final TypeResolver resolver = new TypeResolver();
#Override
public Object handleValidatedValue(final Optional<?> optional) {
return optional.orNull();
}
#Override
public Type getValidatedValueType(final Type type) {
ResolvedType resolvedType = resolver.resolve(type);
return resolvedType.typeParametersFor(Optional.class).get(0).getErasedType();
}
}
Related
I'm try to define a custome annotation include #Configuration and #ImportResource
but #ImportResource doesn't work
Any suggestions?
#Documented
#Configuration
#ImportResource
#Target({ElementType.TYPE})
#Order(Ordered.HIGHEST_PRECEDENCE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EnableXXConfiguration {
#AliasFor(annotation = ImportResource.class , attribute = "value")
String[] value() default {};
}
#ImportResource contains two attributes value and locations. The value attribute is ultimately alias for locations attribute so using either of the aliases works fine. Keeping your Custom annotation(EnableXXConfiguration) declaration (the one using value attribute) as it, use below code snippet.
#EnableXXConfiguration(value = { "context1.xml", "com/example/stackoverflow/context2.xml"})
public class DemoApp {
#Autowired
private BeanA beanA;
#Autowired
private BeanB beanB;
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoApp.class);
DemoApp demoAppObj = (DemoApp) context.getBean("demoApp");
System.out.println("BeanA member: " + demoAppObj.getBeanA());
System.out.println("BeanB member: " + demoAppObj.getBeanB());
}
public BeanA getBeanA() {
return beanA;
}
public BeanB getBeanB() {
return beanB;
}
}
Assume we are using two xmlss placed at two different locations. context1.xml is placed in resource folder(src/main/resource) and context2.xml is placed at any other location (here at: src/main/java/com/example/stackoverflow)
context1.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanA" class="com.example.stackoverflow.BeanA" />
</beans>
context2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanB" class="com.example.stackoverflow.BeanB" />
</beans>
I have some programmatically created beans that I am initializing via AutowireCapableBeanFactory.autowireBean() as shown below:
spring.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:annotation-config/>
<bean id="MyService" class="...">
<property name="someProp" value="primitiveValue"/>
</bean>
<bean id="MyBean" class="...">
<property name="someString" value="primitiveValue"/>
</bean>
</beans>
MyBean.java
public class MyBean implements InitializingBean {
#Autowired MyService myService;
private String someString;
public void setSomeString (String someString) {
this.someString = someString;
}
public void afterPropertiesSet () {}
}
Caller:
MyBean bean = new MyBean(arg1, arg2, arg3);
autowireCapableBeanFactory.autowireBean(bean);
This correctly autowires bean.myService as expected. However it does not populate primitive properties like bean.someString.
Looking at the docs and this answer, I though something like this would work:
MyBean bean = new MyBean(arg1, arg2, arg3);
autowireCapableBeanFactory.autowireBean(bean);
autowireCapableBeanFactory.initializeBean(bean, "name");
But alas, someString is still null. I have found lots of references stating what will not work to initialize class properties, but nothing showing what will work.
Any ideas?
Found I could use AutowireCapableBeanFactory.applyBeanPropertyValues() to accomplish what I wanted. Code to inject both #Autowired beans and primitive properties looks like this:
#Autowired AutowireCapableBeanFactory beanFactory;
...
MyBean bean = new MyBean();
beanFactory.autowireBean(bean);
beanFactory.applyBeanPropertyValues(bean, bean.getClass().getSimpleName());
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spring.dto.Car2' available
Controller.java -
public class Controller {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("configu.xml");
Car2 c2 = (Car2) context.getBean(Car2.class);
System.out.println(c2);
}
}
Car2.java -
#ToString #Component
public class Car2 {
#Autowired
private Engine engine;
}
Engine.java -
#Setter #ToString
public class Engine {
private String modelYear;
}
configu.xml -
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.spring.dto.Car2" />
<context:annotation-config />
<bean class="com.spring.dto.Engine">
<property name="modelYear" value="2015"></property>
</bean>
</beans>
please ignore the annotation #ToString and #Setter- I am using Lombok project for my simplicity.
I think the error is here:
<context:component-scan base-package="com.spring.dto.Car2" />
The value should be a package, not a class. Change it to "com.spring.dto", then it should work.
My application uses struts and spring frameworks. I have a class FormA which has an autowired property in it. When I try to instantiate it while writing unit tests I get a Null Pointer Exception. Here is my code.
My ClassA:
public class FormA{
private String propertyOne;
#Autowired
private ServiceClass service;
public FormA(){
}
}
My unit test method:
#Test
public void testFormA(){
FormA classObj = new FormA();
}
#Autowired only works when object life cycle is managed by Spring.
You'll need to run your tests with #RunWith(SpringJUnit4ClassRunner.class), and instead of instantiating FormA manually, inject it in the test class as well, using #Autowired.
When you create an object by new, autowire\inject don't work...
as workaround you can try this:
create your template bean of NotesPanel
<bean id="notesPanel" class="..." scope="prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
and create an istance in this way
applicationContext.getBean("notesPanel");
PROTOTYPE : This scopes a single bean definition to have any number of object instances.
anyway a unit test should be
Test class
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration(locations = { "classpath:META-INF/your-spring-context.xml" })
public class UserServiceTest extends AbstractJUnit4SpringContextTests {
#Autowired
private UserService userService;
#Test
public void testName() throws Exception {
List<UserEntity> userEntities = userService.getAllUsers();
Assert.assertNotNull(userEntities);
}
}
your-spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="userService" class="java.package.UserServiceImpl"/>
</beans>
I'm trying to replicate something that works with XML config using annotated configuration classes. The problem I'm hitting is that property sources defined in the child context are not accessible.
The xml that works looks like
Parent context :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="proxyChannelQueue" class="java.util.concurrent.ArrayBlockingQueue">
<constructor-arg value="10"/>
</bean>
</beans>
Child Context :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="proxy-host.properties"/>
<bean class="org.eclipse.jetty.server.Server"
p:handler-ref="proxyHostHandler"
init-method="start">
<constructor-arg value="${proxyHostPort}"/>
</bean>
<bean id="proxyHostHandler" class="com.sjl.web.ProxyHostHandler"
p:proxyChannelQueue-ref="proxyChannelQueue"/>
</beans>
Start up code :
ClassPathXmlApplicationContext parentContext = new ClassPathXmlApplicationContext("test/parent-context.xml");
ClassPathXmlApplicationContext childContext = new ClassPathXmlApplicationContext(new String[] {"test/child-context.xml"}, parentContext);
My attempt at doing this using configuration classes looks like.
Parent Context :
#Configuration
public class ParentConfiguration {
#Bean(name = "proxyChannelQueue")
public BlockingQueue<ProxyChannel> getProxyChannelQueue() {
return new ArrayBlockingQueue<ProxyChannel>(10);
}
}
Child Context :
#Configuration
#PropertySource("classpath:proxy-host.properties")
public class ChildContext {
private static final Logger LOGGER = LoggerFactory.getLogger(ChildContext.class);
#Autowired
private Environment environment;
#Resource(name = "proxyChannelQueue")
private BlockingQueue<ProxyChannel> proxyChannelQueue;
public static void main(String[] args) {
new HierarchicalAnnotationConfigApplicationContext(ChildContext.class);
}
#Bean
public Server getJettyServer() throws Exception {
int proxyHostPort = environment.getProperty("proxyHostPort", Integer.class);
Server server = new Server(proxyHostPort);
server.setHandler(getHandler());
server.start();
return server;
}
#Bean
public Handler getHandler() {
ProxyHostHandler proxyHostHandler = new ProxyHostHandler();
proxyHostHandler.setProxyChannelQueue(proxyChannelQueue);
return proxyHostHandler;
}
}
Start up code :
AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfiguration.class);
AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
childContext.setParent(parentContext);
childContext.register(ChildContext.class);
childContext.refresh();
I'm getting a null pointer while trying to retrieve the proxyHostPort within the ChildContext getJettyServer method. Inspecting the environment variable shows that it contains only 2 property sources (systemProperties and systemEnvironment) and not the 3 I expect.
The same configuration works if I run them as a single combined context. E.g. :
AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfiguration.class, ChildContext.class);
However I want the isolation that using parent contexts provide.
Cheers,
Peter