Can univocity execute validators in OR way insted of AND? - java

I would like to know if there is any way to execute the validators in an OR operator way insted of AND. Currently if the first fails, he doesn't run the other two, however I need him to run them all to return to the user all the respective fixes that he should apply to the file.
I have something like:
#Validate(nullable = false, validators = { NumericValidator.class, LengthValidator.class, DataValidator.class })
I don't create a single validation since I would like to create general validations and just call the specific depending on the field.
Thanks in advance.

I solved building a class like
import java.util.HashSet;
import java.util.Set;
import com.univocity.parsers.conversions.Validator;
import co.com.app.constantes.Constants;
public class CustomValidator implements Validator<Object> {
protected Set<Validator<Object>> validators = new HashSet<>();
public CustomValidator() {
super();
}
#Override
public String validate(Object value) {
Set<String> errors = new HashSet<>();
validators.forEach(validator -> {
String error = validator.validate(value);
if (error != null) {
errors.add(error);
}
});
if (errors.isEmpty()) {
return null;
}
return String.join(Constants.COMMA, errors);
}
}
Then I create a Validator like
public class FieldValidator extends CustomValidator {
public FieldValidator() {
validators.add(new NumericValidator());
validators.add(new LengthValidator(1, 11));
}
}
And in the DTO I used something like
#Parsed(index = 0)
#NullString(nulls = { Constants.NULL_VALUE, Constants.EMPTY_VALUE })
#Validate(nullable = false, validators = { FieldValidator.class })
private Long field;

Related

How to pass custom data type to cucumber-jvm stepdef in latest 4.x version

I have recently upgraded to latest 4.x version of cucumber-jvm in my project in order to leverage parallel execution feature of cucumber. But I am facing this issue now with respect to having custom data type as parameter. Earlier we had an interface called Transformer which we can implement for custom data types, now in the latest version I've found TypeRegistryConfigurer interface which needs to be implemented. But it is not recognising the step as I would've expected. Details as follows:
Gherkin Step:
Given user gets random(3,true,true) parameter
StepDefinition:
#Given("user gets {random} parameter")
public void paramTest(RandomString randomString) {
System.out.println(randomString.string);
}
RandomString class:
public class RandomString {
public String string;
public RandomString(String string) {
Matcher m = Pattern.compile("random\\((.?)\\)").matcher(string);
String t = "";
while (m.find()) {
t = m.group(1);
}
boolean isAlpha = true, isNum = true;
if (t.length() > 0) {
String[] placeholders = t.split(",");
if (placeholders.length == 3) {
int count = Integer.parseInt(placeholders[0]);
isAlpha = Boolean.valueOf(placeholders[1]);
isNum = Boolean.valueOf(placeholders[2]);
this.string = string.replaceAll("random(.*)", RandomStringUtils.random(count, isAlpha, isNum));
}
}
this.string = string.replaceAll("random(.*)", RandomStringUtils.random(3, isAlpha, isNum));
}
}
TypeRegistryImpl:
public class TypeRegistryConfiguration implements TypeRegistryConfigurer {
#Override
public Locale locale() {
return Locale.ENGLISH;
}
#Override
public void configureTypeRegistry(TypeRegistry typeRegistry) {
typeRegistry.defineParameterType(new ParameterType<>(
"random",
"random([0-9],true|false,true|false)",
RandomString.class,
RandomString::new)
);
}
}
Your string random(3,true,true) does not match the pattern used in:
typeRegistry.defineParameterType(new ParameterType<>(
"random",
"random([0-9],true|false,true|false)",
RandomString.class,
RandomString::new)
);
You can verify this by creating the pattern and testing it:
import java.util.regex.Pattern;
class Scratch {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("random([0-9],true|false,true|false)");
// prints out false
System.out.println(pattern.matcher("random(3,true,true)").matches());
}
}
You have also not used a matching pattern in RandomString.
I've found the solution after trial and hit and going through some examples from some Unit Tests in cucumber-jvm project.
Modified StepDef:
#Given("user gets {random} parameter")
public void paramTest(String randomString) {
System.out.println(randomString.string);
}
TypeRegistryConfigurer Implementation:
import cucumber.api.TypeRegistry;
import cucumber.api.TypeRegistryConfigurer;
import io.cucumber.cucumberexpressions.CaptureGroupTransformer;
import io.cucumber.cucumberexpressions.ParameterType;
import org.apache.commons.lang3.RandomStringUtils;
import java.util.Locale;
public class TypeRegistryConfiguration implements TypeRegistryConfigurer {
#Override
public Locale locale() {
return Locale.ENGLISH;
}
#Override
public void configureTypeRegistry(TypeRegistry typeRegistry) {
typeRegistry.defineParameterType(new ParameterType<>(
"random",
"random\\(([0-9]+),(true|false),(true|false)\\)",
String.class,
new CaptureGroupTransformer<>() {
#Override
public String transform(String[] args) {
return RandomStringUtils.random(Integer.parseInt(args[0]), Boolean.valueOf(args[1]), Boolean.valueOf(args[2]));
}
})
);
}
}

Custom attribute factories for MeanBean EqualsMethodTester and HashCodeMethodTester

Is it possible to configure custom factories to generate values for the EqualsMethodTester and HashCodeMethodTester classes from org.meanbean.test? When I pass the Configuration which works for BeanTester to EqualsMethodTester, I get the following messages in the error traceback:
org.meanbean.factories.ObjectCreationException: Failed to create a value for property [demoUrl].
Failed to find suitable Factory for property=[demoUrl] of type=[class java.net.URL]. Please register a custom Factory.
org.meanbean.factories.ObjectCreationException: Failed to instantiate object of type [java.net.URL] due to NoSuchMethodException.
java.lang.NoSuchMethodException: java.net.URL.<init>()
(Both EqualsMethodTester and HashCodeMethodTester give this error. Adding "demoUrl" to the list of insignificantProperties for EqualsMethodTester().testEqualsMethod() makes no difference. Stepping through the code implies my URLFactory.create() isn't called at all.)
I do not see any options for passing the configuration into HashCodeMethodTester. I've skimmed documentation at the following sites, but have found neither a solution nor acknowledgement of the missing functionality: http://meanbean.sourceforge.net/docs/2.0.3/public/org/meanbean/test/EqualsMethodTester.html
http://meanbean.sourceforge.net/docs/2.0.3/public/org/meanbean/test/HashCodeMethodTester.html
http://meanbean.sourceforge.net/docs/2.0.3/public/org/meanbean/test/ConfigurationBuilder.html
http://meanbean.sourceforge.net/docs/2.0.3/Mean_Bean_2.0.3_User_Guide.pdf
(I'm using MeanBean v 2.0.3 and Java 1.8.)
I have the following class, using java.net.URL:
public class Product {
private String name;
private URL demoUrl;
public Product(){
super();
}
public int hashCode() {
return Objects.hash(getName(), whitehawkSKU);
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
Product other = (Product) obj;
return Objects.equals(getName(), other.getName());
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public URL getDemoUrl() {
return demoUrl;
}
public void setDemoUrl(URL demoUrl) {
this.demoUrl = demoUrl;
}
}
To handle the URL field, I created a custom factory, as per meanbean: failed to test bean with arrays and it works for BeanTester but not for EqualsMethodTester:
import org.meanbean.lang.Factory;
import java.net.MalformedURLException;
import java.net.URL;
public class URLFactory implements Factory<URL> {
private static int counter = 0;
#Override
public URL create() {
String host = "http://test." + counter + ".url/";
try {
return new URL(host);
}
catch (MalformedURLException except) {
return null;
}
}
}
My test methods are as follows:
private Configuration configureMeanBeanTests() {
URLFactory urlFactory = new URLFactory();
return new ConfigurationBuilder()
.overrideFactory("demoUrl", urlFactory).build();
}
#Test
public void testAccessors() {
new BeanTester().testBean(Product.class, configureMeanBeanTests());
}
#Test
public void testEquals() {
new EqualsMethodTester().testEqualsMethod(
Product.class,
configureMeanBeanTests(),
"name",
"demoUrl"
);
}
#Test
public void testHashCode() {
new HashCodeMethodTester().testHashCodeMethod(Product.class);
}
What am I missing?
It looks like the EqualsMethodTester().testEqualsMethod() needs a EquivalentFactory in that particular case due to the use java.net.URL that does not provide a default empty constructor. So when BasicNewObjectInstanceFactory.create() is called for java.net.URL the call the clazz.getDeclaredConstructor() throw an exception Method threw 'java.lang.NoSuchMethodException' exception..
Basically you just have to implement a EquivalentFactory.
An anonymous implementation could be:
private EquivalentFactory<Product> productEquivalentFactory = new EquivalentFactory<Product>() {
#Override
public Product create() {
Product p = new Product();
try {
p.setDemoUrl(new URL("http://test.1.url/"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
p.setName("test");
return p;
}
};
It has to be used with the custom configuration that you already have:
new EqualsMethodTester().testEqualsMethod(productEquivalentFactory, configureMeanBeanTests(), "demoUrl");`
For the hashcode just use the equivalent factory and it does the job.
I tested it and it is working.

How to read a Thymeleaf template from DB in Thymeleaf 3.0.5?

We're upgrading from Thymeleaf 2.1 to 3.0.5. Our current set up (before upgrading) has many thymeleaf templates defined and stored in a database table.
When we attempt to upgrade to 3.x our 2.1 code no longer works...ok fine but we can't find any good examples on how to do basically the same thing with Thymeleaf 3.0.5. Has anyone implemented this?
Even a decent example of how to implement org.thymeleaf.templateresolver.StringTemplateResolver would probably push us in the right direction...but we can't find anything on that either.
This is what we used in 2.1:
public class ThymeleafTemplateResolver extends TemplateResolver {
private final static String PREFIX = "";
public ThymeleafTemplateResolver() {
setResourceResolver(new DbResourceResolver());
setResolvablePatterns(Sets.newHashSet(PREFIX + "*"));
}
#Override
protected String computeResourceName(TemplateProcessingParameters params) {
String templateName = params.getTemplateName();
return templateName.substring(PREFIX.length());
}
private class DbResourceResolver implements IResourceResolver {
#Override
public InputStream getResourceAsStream(TemplateProcessingParameters params, String template) {
ThymeleafTemplateDao thymeleaftemplateDao = ApplicationContextProvider.getApplicationContext().getBean(ThymeleafTemplateDao.class);
ThymeleafTemplate thymeleafTemplate = thymeleaftemplateDao.findByTemplate(template);
if (thymeleafTemplate != null) {
return new ByteArrayInputStream(thymeleafTemplate.getContent().getBytes());
}
return null;
}
#Override
public String getName() {
return "dbResourceResolver";
}
}
}
Any help is appreciated...
Through mostly trial and error I was able to piece this together. Posting it here to help the next person looking for something similar.
This is made easier in the newer version of Thymeleaf. All one needs to do now is to extend StringTemplateResolver.
import java.util.Map;
import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.templateresolver.StringTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import com.google.common.collect.Sets;
public class ThymeleafDatabaseResourceResolver extends StringTemplateResolver {
private final static String PREFIX = "";
#Autowired ThymeleafTemplateDao thymeleaftemplateDao;
public ThymeleafDatabaseResourceResolver() {
setResolvablePatterns(Sets.newHashSet(PREFIX + "*"));
}
#Override
protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, Map<String, Object> templateResolutionAttributes) {
// ThymeleafTemplate is our internal object that contains the content.
// You should change this to match you're set up.
ThymeleafTemplateDao thymeleaftemplateDao = ApplicationContextProvider.getApplicationContext().getBean(ThymeleafTemplateDao.class);
ThymeleafTemplate thymeleafTemplate = thymeleaftemplateDao.findByTemplateName(template);
if (thymeleafTemplate != null) {
return super.computeTemplateResource(configuration, ownerTemplate, thymeleafTemplate.getContent(), templateResolutionAttributes);
}
return null;
}
}

It is possible to check if import is wrong? while writing a custom rule

I would like to write a java rule Will generate a issue if an imported class is an APIClass annotation and the imported class has issues. I am following this tutorial.
The code:
First, I wrote a simple rule:
#Rule( key = "ForbidClassVariables", name = "ForbidClassVariables")
public class ForbidClassVariables extends BaseTreeVisitor implements JavaFileScanner {
private JavaFileScannerContext context;
#Override
public void scanFile(JavaFileScannerContext context) {
this.context = context;
if (context.getSemanticModel() != null) {
scan(context.getTree());
}
}
#Override
public void visitClass(ClassTree tree) {
if (tree.modifiers().annotations().size() > 0 && hasAnnotation(tree.modifiers().annotations(), "APIClass")) {
if (hasClassVariables(tree)) {
this.context.reportIssue(this, tree.simpleName(), "Do not use class variables on API Classes.");
}
}
super.visitClass(tree);
}
private boolean hasAnnotation(List<AnnotationTree> annotations, String annotationName) {
for (AnnotationTree annotation : annotations) {
if (annotation.annotationType().is(Tree.Kind.IDENTIFIER)
&& ((IdentifierTree) annotation.annotationType()).name().equals(annotationName)) {
return true;
}
}
return false;
}
private boolean hasClassVariables(ClassTree tree) {
for (Tree member : tree.members()) {
if (member.is(Tree.Kind.VARIABLE)) {
VariableTree variableTree = (VariableTree) member;
Symbol symbol = variableTree.symbol();
if (!symbol.isStatic() || !symbol.isFinal()) {
return true;
}
}
}
return false;
}
}
I created a test class file ExampleA.java
package br.com.test;
#APIClass
public class ExampleA {
private String name;
}
When I run the test, generates an error on line 4, It was as expected.
The point of the problem: I created another rule:
#Rule( key = "CheckIFClassIsOK", name = "CheckIFClassIsOK")
public class CheckIFImportedClassIsOK extends BaseTreeVisitor implements JavaFileScanner{
private JavaFileScannerContext context;
#Override
public void scanFile(JavaFileScannerContext context) {
this.context = context;
if (context.getSemanticModel() != null) {
scan(context.getTree());
}
}
#Override
public void visitImport(ImportTree tree) {
IdentifierTree identifier = ((MemberSelectExpressionTree) tree.qualifiedIdentifier()).identifier();
System.out.println(identifier); // Shows ExampleA
// At this point I need re-scan ExampleA class and IF the scan generate any issue
// Will generate another here Issue on ExampleB
super.visitImport(tree);
}
}
And used this file to test:
import br.com.test.ExampleA;
public class ExampleB {
private ExampleA exampleA;
}
The problem is, when I am visiting an import, if the imported class has an APIClass annotation and has issues, it will generate an issue on ExampleB.java to avoid using this import because has an issue. I have searched a lot on the Tree classes, but I didn't find anything useful. I think I need to force the re-scan on ExampleA.java, but how? Anyone have ideas?
Sonar version: 6.2
Java plugin version: 4.5.0.8398
Thanks for attention
Unfortunately, this is not possible. There is no way in the API to request parsed tree from another file. However you are able to retrieve semantic information about members in class ExampleB, but this doesn't include annotations.

spring data mongodb Cannot perform cascade save on child object without id set

I am using #CascadeSave to save child object in separate collection.
My Document classes are :
public class FbUserProfile{
#Id
private long id;
#DBRef(lazy=true)
#CascadeSave()
private Set<FacebookFriend> friends;
#DBRef(lazy=true)
#CascadeSave()
private Set<FacebookFriendList> customFriendList;
}
public class FacebookFriend{
#Id
private long id;
private String name;
}
public class FacebookFriendList{
#Id
private long id;
private String name;
private String list_type;
}
I add some object in both friends,customFriendList.
and try to update fbUserProfile object using:
mongoTemplate.save(fbUserProfile);
note: fbUserProfile already exists in db. Now I am updating this
Error Message: Cannot perform cascade save on child object without id set
If I remove #CascadeSave. It works fine for me. How I can Cascade set objects.
I am also using #CascadeSave with other objects. Its working fine but they are not set object.
I found the same tutorials somewhere else: Baeldung's and JavaCodeGeeks (this is the one i've followed)
I've had that same problem, and I could solve it.
It happens when you try to persist a collection. It doesn't matter that the collection's items have the #Id, because the collection itself won't have it. I edited the code in the EventListener's onBeforeConvert to check if the field you're trying to CascadeSave is a collection (in my case a List). If it's a list, you just cycle through it checking each individual item for #Id and saving them.
If it's not a collection you still have to persist them the same way you did before
#Override
public void onBeforeConvert(Object source) {
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
#Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){
final Object fieldValue = field.get(source);
if(fieldValue instanceof List<?>){
for (Object item : (List<?>)fieldValue){
checkNSave(item);
}
}else{
checkNSave(fieldValue);
}
}
}
});
}
private void checkNSave(Object fieldValue){
DbRefFieldCallback callback = new DbRefFieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
if (!callback.isIdFound()){
throw new MappingException("Oops, something went wrong. Child doesn't have #Id?");
}
mongoOperations.save(fieldValue);
}
The best way to set an ID on the dependent child object is to write a listener class by extending AbstractMongoEventListener class and override the onConvert() method.
public class CustomMongoEventListener extends
AbstractMongoEventListener<Object> {
#Autowired
private MongoOperations mongoOperations;
#Override
public void onBeforeConvert(final Object entity) {
if (entity.id == null || entity.id.isEmpty()) {
entity.id = generateGuid(); //generate random sequence ID
}
public static String generateGuid() {
SecureRandom randomGen = new SecureRandom();
byte[] byteArray = new byte[16];
randomGen.nextBytes(byteArray);
return new Base32().encodeToString(byteArray).substring(0,26);
}
}
Finally register your custom listener in `your configuration file. For annotation approach use the following code to register :
#Bean
public CustomMongoEventListener cascadingMongoEventListener() {
return new CustomMongoEventListener();
}
The above solution works fine incase if you have a list. But we can avoid firing a save query for each element from the list, as it reduces the performance. Here is the solution I have found out of the above code.
#Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
Object source = event.getSource();
ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
#Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){
final Object fieldValue = field.get(source);
if(fieldValue instanceof List<?>){
for (Object item : (List<?>)fieldValue){
checkNAdd(item);
}
}else{
checkNAdd(fieldValue);
}
mongoOperations.insertAll(documents);
}
}
});
}
private void checkNAdd(Object fieldValue){
DbRefFieldCallback callback = new DbRefFieldCallback();
ReflectionUtils.doWithFields(fieldValue.getClass(), callback);
if (!callback.isIdFound()){
throw new MappingException("Oops, something went wrong. Child doesn't have #Id?");
}
documents.add(fieldValue);
}
Okey I extend the class and it will check if the document is exist if it exist it will update the document else it insert the document:
#Component
class GenericCascadeMongo(
private val mongoTemplate: MongoTemplate
) : AbstractMongoEventListener<Any>() {
override fun onBeforeConvert(event: BeforeConvertEvent<Any?>) {
val source = event.source
?: return
ReflectionUtils.doWithFields(source.javaClass) { field ->
ReflectionUtils.makeAccessible(field)
if (field.isAnnotationPresent(DBRef::class.java) && field.isAnnotationPresent(CascadeSave::class.java)) {
val fieldValue = field[source]
?: return#doWithFields
if (fieldValue is List<*>) {
fieldValue.filterNotNull().forEach {
checkAndSave(it)
}
} else {
checkAndSave(fieldValue)
}
}
}
}
private fun checkAndSave(fieldValue: Any) {
try {
val callback = DbRefFieldCallback(fieldValue)
ReflectionUtils.doWithFields(fieldValue.javaClass, callback)
if (!callback.isIdFound && callback.id == null) {
mongoTemplate.insert(fieldValue)
}
if (callback.id != null) {
val findById = mongoTemplate.exists(Query(Criteria.where(MConst.MONGO_ID).`is`(callback.id)), fieldValue.javaClass)
if (findById) {
mongoTemplate.save(fieldValue)
} else {
mongoTemplate.insert(fieldValue)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private class DbRefFieldCallback(val fieldValue: Any?) : FieldCallback {
var isIdFound = false
private set
var id: String? = null
private set
#Throws(IllegalArgumentException::class, IllegalAccessException::class)
override fun doWith(field: Field) {
ReflectionUtils.makeAccessible(field)
if (field.isAnnotationPresent(Id::class.java)) {
isIdFound = true
id = ReflectionUtils.getField(field, fieldValue)?.toString()
}
}
}
}

Categories

Resources