How can I add custom string preprocessing in JOOQ to sanitize strings? - jooq

I want to fix the errors, which sometimes happened in my app:
ERROR: invalid byte sequence for encoding "UTF8": 0x00; nested exception is org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00
I think right way to solve it is to sanitize all text fields before insertion to database with
this.replace("\\u0000", "")
The question is how to implement the converter or custom binding in one place to force JOOQ invoke this replace function?

Using jOOQ's Converter or Binding
I'm assuming this is about JSON and PostgreSQL? See also: org.jooq.exception.DataAccessException: unsupported Unicode escape sequence \u0000
It seems that a Converter<JSON, JSON> (or JSONB, respectively) would suffice?
Converter.ofNullable(JSON.class, JSON.class,
j -> j,
j -> JSON.json(j.data().replace("\\u0000", ""))
);
And then, attach that everywhere using a forcedType:
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.17.0.xsd">
<generator>
<database>
<forcedTypes>
<forcedType>
<userType>org.jooq.JSON</userType>
<converter>Converter.ofNullable(JSON.class, JSON.class,
j -> j,
j -> JSON.json(j.data().replace("\\u0000", ""))
)</converter>
<includeTypes>(?i:json)</includeTypes>
</forcedType>
</forcedTypes>
</database>
</generator>
</configuration>
Using JDBC
You could, of course, also just proxy JDBC and patch PreparedStatement::setString:
#Override
public void setString(int parameterIndex, String x) throws SQLException {
if (x == null)
delegate.setString(parameterIndex, x);
else
delegate.setString(parameterIndex, x.replace("\\u0000", "");
}
// Also all the other methods that might accept strings
A simple way to approach this is by using jOOQ's own JDBC proxy utility types, to avoid implementing the entire JDBC API:
org.jooq.tools.jdbc.DefaultConnection
org.jooq.tools.jdbc.DefaultPreparedStatement
This will handle things on a lower level, including when you don't use jOOQ. However, if you're using inline values, then those won't be converted by this approach, as those values are transparent to JDBC

So what I've did to solve the problem:
Added custom binding:
class PostgresStringsBinding : Binding<String, String> {
override fun converter(): Converter<String, String> {
return object : Converter<String, String> {
override fun from(dbString: String?): String? {
return dbString
}
override fun to(string: String?): String? {
return string?.withEscapedNullChars()
}
override fun fromType(): Class<String> {
return String::class.java
}
override fun toType(): Class<String> {
return String::class.java
}
}
}
#Throws(SQLException::class)
override fun sql(ctx: BindingSQLContext<String>) {
if (ctx.render().paramType() == ParamType.INLINED) ctx.render()
.visit(DSL.inline(ctx.convert(converter()).value())).sql("::text") else ctx.render().sql("?::text")
}
#Throws(SQLException::class)
override fun register(ctx: BindingRegisterContext<String>) {
ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR)
}
#Throws(SQLException::class)
override fun set(ctx: BindingSetStatementContext<String>) {
ctx.statement().setString(ctx.index(), Objects.toString(ctx.convert(converter()).value(), null))
}
#Throws(SQLException::class)
override fun get(ctx: BindingGetResultSetContext<String>) {
ctx.convert(converter()).value(ctx.resultSet().getString(ctx.index()))
}
#Throws(SQLException::class)
override fun get(ctx: BindingGetStatementContext<String>) {
ctx.convert(converter()).value(ctx.statement().getString(ctx.index()))
}
#Throws(SQLException::class)
override fun set(ctx: BindingSetSQLOutputContext<String>) {
throw SQLFeatureNotSupportedException()
}
#Throws(SQLException::class)
override fun get(ctx: BindingGetSQLInputContext<String>) {
throw SQLFeatureNotSupportedException()
}
}
and registered it as ForcedType:
ForcedType()
.withUserType("java.lang.String")
.withBinding("org.example.jooqbindings.PostgresStringsBinding")
.withIncludeExpression(".*")
.withIncludeTypes("VARCHAR|TEXT")

Related

C#8 nullable : string.IsNullOrEmpty is not understood by compiler as helping for guarding against null

I am using C# 8 with .NET framework 4.8
I'm currently guarding against a potential string that can be null with IsNullOrWhitespace (same problem with IsNullOrEmpty) , but the compiler is still complaining :
public MyImage? LoadImage(string? filename)
{
if (string.IsNullOrWhiteSpace(filename))
{
return null;
}
return OtherMethod(filename); // here : warning from Visual Studio
}
// signature of other method :
public MyImage OtherMethod(string filepath);
currently, I have workarounds to make the compiler understand :
use null forgiving operator filename!
disable warning by using #pragma warning disable CS8604 // Possible null reference argument.
add another check for null if(string == null || string.IsNullOrWhitespace(filename))
But none of the seems satisfactory, mainly because I'll need to repeat the workaround for each call to IsNullOrEmpty.
Is there any other way to tell the compiler that IsNullOrEmpty effectively guards against null ?
If you don't have .net standard 2.1 or .net core 3, the IsNullOrEmpty is not nullable ready. So, I would create an extension method for this:
#nullable enable
public static class StringExt {
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? data) {
return string.IsNullOrEmpty(data);
}
}
#nullable restore
You also need to activate NotNullWhen attribute like this:
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NotNullWhenAttribute : Attribute {
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
public bool ReturnValue { get; }
}
}

Get the generic type of a List in Groovy

I am building a automated swagger plugin. Here I run through annotated classes.
When we talk about the datatypes of String, Long, etc. is is enough for me use the simpleName method.
But when get to a Class of List, Set, Collection I need to know the generic type.
So how can I do this?
A example of code which do most of the job:
class Foo {
List<String> myString
}
class SomeUtilClass {
static String dataType(Class<?> c) {
return c.simpleName
}
static List<String> dataTypes(Class<?> c) {
return c.metaClass.properties.findAll {MetaProperty metaProperty ->
metaProperty?.field != null
}.collect {dataType(it.type)}
}
}
SomeUtilClass.dataTypes(Foo) // ["List"] but I want something like ["List<String>"]
I found the solution. I can look on the generic type from Cached fields.
See below example:
class SomeUtilClass {
static String dataType(Class<?> c) {
return c.simpleName
}
static List<String> dataTypes(Class<?> c) {
return c.metaClass.properties.findAll {MetaProperty metaProperty ->
metaProperty?.field != null
}.collect {findGenerics(it.type)}
}
static void findGenerics(CachedField t) {
t.field.genericType?.actualTypeArguments.collect {dataType(it)}
}
}

Validating queryparam values jersey

Are there any other ways besides the one below to validate query parameter values i.e. is there a Jersey way to this by mapping to a schema via a wadl. Thank you
#Path("smooth")
#GET
public Response smooth(
#DefaultValue("blue") #QueryParam("min-color") ColorParam minColor,
public class ColorParam extends Color {
public ColorParam(String s) {
super(getRGB(s));
}
private static int getRGB(String s) {
if (s.charAt(0) == '#') {
try {
Color c = Color.decode("0x" + s.substring(1));
return c.getRGB();
} catch (NumberFormatException e) {
throw new WebApplicationException(400);
Unfortunately, there is limited support for validation on current JAX-RS version. But according to the draft for JAX-RS 2.0, it will have much better validation handling in the future.
You can see an example of the new features here.

RequestMapping on presence of one of multiple parameters

I have a Spring3 controller in which I'm using the #RequestMapping annotation. I know I can use the params value to route based on the the presence or lack of a url parameter, but is there a way to route based on the presence of one of two parameters?
Ideally I'd have something like the following:
#RequestMapping(value="/auth", params="error OR problem")
public ModelAndView errorInAuthenticate()
Where I route to errorInAuthenticate if the parameters error OR problem exist.
Unfortunately #RequestMapping params are combined using AND, not OR. (Source)
simply map both params as not required and test them:
#RequestMapping(value="/auth")
public ModelAndView errorInAuthenticate(#RequestParam(value="error", required=false) String errorParam,
#RequestParam(value="problem", required=false) String problemParam) {
if(errorParam != null || problemParam != null) {
//redirect
}
}
You can do it using Spring AOP and create a surrounding aspect for that request mapping.
Create an annotation like the following:
public #interface RequestParameterOrValidation{
String[] value() default {};
}
Then you can annotate your request mapping method with it:
#GetMapping("/test")
#RequestParameterOrValidation(value={"a", "b"})
public void test(
#RequestParam(value = "a", required = false) String a,
#RequestParam(value = "b", required = false) String b) {
// API code goes here...
}
Create an aspect around the annotation. Something like:
#Aspect
#Component
public class RequestParameterOrValidationAspect {
#Around("#annotation(x.y.z.RequestParameterOrValidation) && execution(public * *(..))")
public Object time(final ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args= joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
RequestParameterOrValidation requestParamsOrValidation= method.getAnnotation(RequestParameterOrValidation.class);
String[] params=requestParamsOrValidation.value();
boolean isValid=false;
for (int argIndex = 0; argIndex < args.length; argIndex++) {
for (Annotation annotation : parameterAnnotations[argIndex]) {
if (!(annotation instanceof RequestParam))
continue;
RequestParam requestParam = (RequestParam) annotation;
if (Arrays.stream(params).anyMatch(requestParam.value()::equals) && args[argIndex]!=null) {
// Atleast one request param exist so its a valid value
return joinPoint.proceed();
}
}
}
throw new IllegalArgumentException("illegal request");
}
}
Note:- that it would be a good option to return 400 BAD REQUEST here since the request was not valid. Depends on the context, of course, but this is a general rule of thumb to start with.

How to remove the surrounding ??? when message is not found in bundle

In JSF 2.0, if a message is not found in the message bundle, then by default, the key is surrounded with ???. This is a very usable hint during development. However, in my particular case, I really would like that those ??? were not present. I prefer that only the key would be rendered.
E.g. when I do
#{msg.hello}
and the key 'hello' doesn't exist, then the page displays
???hello???
but I would like to show the bare key
hello
The message bundle is loaded in a JSF page as follows:
<f:loadBundle basename="resources.text" var="msg" />
The <f:loadBundle> tag doesn't seem to have an attribute to manipulate the way values are retrieved from that bundle. Should I overwrite some class or how to intercept the way messages are retrieved from the bundle?
I've found a very interesting article on this: Context Sensitive Resource Bundle entries in JavaServer Faces applications – going beyond plain language, region & variant locales. However, in my case, I just want to omit the ???. I think this solution is rather complicated. How can I achieve it anyway?
The basename can point to a fullworthy ResourceBundle class. E.g.
<f:loadBundle basename="resources.Text" var="msg" />
with
package resources;
public class Text extends ResourceBundle {
public Text() {
setParent(getBundle("resources.text", FacesContext.getCurrentInstance().getViewRoot().getLocale()));
}
#Override
public Enumeration<String> getKeys() {
return parent.getKeys();
}
#Override
protected Object handleGetObject(String key) {
return parent.getObject(key);
}
}
You can overridde the bundle message handling in handleGetObject. JSF by default (by spec) calls getObject(), catches MissingResourceException and returns "???" + key + "???" when caught. You can do it differently.
#Override
protected Object handleGetObject(String key) {
try {
return parent.getObject(key);
} catch (MissingResourceException e) {
return key;
}
}
You could also create a simple bean that takes care of the string manipulation. This approach is a lot better if you don't need to remove the default surroundings everywhere but only on a specific place(s). The second function is a lot safer to use, since it also takes care of the case where translation starts and ends with the ???.
#ApplicationScoped
#Named
public class LocaleUtils {
public String getMessage(String s) {
return clearMessage(s);
}
public Object getMessage(ResourceBundle propertyResourceBundle, String key) {
try {
return propertyResourceBundle.getObject(key);
}
catch (MissingResourceException e) {
return clearMessage(key);
}
}
private static String clearMessage(String s) {
String clearMessage = s;
String prefix = "???", suffix = "???";
if (s != null && s.startsWith(prefix) && s.endsWith(suffix)) {
s = s.substring(prefix.length());
clearMessage = s.substring(0, s.length() - suffix.length());
}
return clearMessage;
}
}
Usage:
<h:outputText value="#{localeUtils.getMessage(msg['hello'])}"/>
<h:outputText value="#{localeUtils.getMessage(msg, 'hello')}"/>

Resources