Escape single quote URL query parameter in Jersey / Jackson - jackson

Long story, I need to protect some legacy code against SQL injection. Prepared statements not an option.
API are first handled by Jersey and the JSON Object deserialisation is Jackon
So, one thing I'd like is to escape all the occurrences of '. So when Jackson / Jersey deserialises the query parameter from the API, anytime it sees a ' it will replace it with a '' Is this possible?

Have you tried using a custom string deserializer?
public class CustomStringDeserializer extends StdScalarDeserializer<String> {
protected CustomStringDeserializer() {
super(String.class);
}
#Override
public String deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
String originalValue = parser.getValueAsString();
String escapedValue = null;
if (originalValue != null) {
escapedValue = originalValue.replace("'", "''");
}
return escapedValue;
}
}

Related

Unable to get traceId when using #feignClient

I have 2 services S1 and S2. Calling S2 using annotated Feign client(#FeignClient) from S1. The issue is, I am unable to get traceId in S2.
But when I try to call S2 using RestTemplate it works.
Any help will be appreciated
Edited:
I have find out the cause actually I am using Feign.Builder below is sample code which builds fiegn client.
#ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
SetterFactory setterFactory = new SetterFactory() {
#Override
public HystrixCommand.Setter create(Target<?> target, Method method) {
String groupKey = target.name();
String commandKey = target.name();
return HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
}
};
return HystrixFeign.builder().setterFactory(setterFactory);
}
Actually due to above config.. SleuthFeignHystrixBuilder is not invoked.
I need to set HysterixCommandKey in my format.. thats why need above config.
How can it work with spring-sleuth ?
I have implemented Spring's BeanPostProcessor interface and then set 'setterFactory'. Refer to below sample code
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof HystrixFeign.Builder) {
((HystrixFeign.Builder)bean).setterFactory(new SetterFactory() {
#Override
public HystrixCommand.Setter create(Target<?> target, Method method) {
String groupKey = target.name();
String commandKey = target.name();
return HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
}
});
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

Jackson remove "e" from BigDecimal [duplicate]

I am using a library com.fasterxml.jackson library for JsonSchema,
I am creating an IntegerSchema object, when I set range for integer schema using below code:
main(){
IntegerSchema intSchema = new IntegerSchema();
// setMaximum accepts Double object
intSchema.setMaximum(new Double(102000000));
// setMaximum accepts Double object
intSchema.setMinimum(new Double(100));
printJsonSchema(intSchema);
}
public void printJsonSchema(JsonSchema schema){
ObjectMapper mapper = new ObjectMapper();
try {
logger.info(mapper.writeValueAsString(schema));
} catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
}
When I convert IntegerSchema to string using ObjectMapper getting below response:
{"type":"integer","maximum":1.02E8,"minimum":100.0}
maximum and minimum values are getting converted to scientific notation.
But I need output in non scientific notation as below:
{"type":"integer","maximum":102000000,"minimum":100}
I cannot change IntegerSchema class.
Please suggest how to get the required output without extending IntegerSchema class?
Thanks in advance
this is a java issue somewhat I believe. If you debug your program, your Double will always be displayed scientifically, so what we'll want is to force it into a String. This can be achieved in Java in multiple ways, and you can look it up here:
How to print double value without scientific notation using Java?
In terms of your specific question about Jackson, I've written up some code for you:
public class ObjectMapperTest {
public static void main(String[] args) throws JsonProcessingException {
IntegerSchema schema = new IntegerSchema();
schema.type = "Int";
schema.max = 10200000000d;
schema.min = 100d;
ObjectMapper m = new ObjectMapper();
System.out.println(m.writeValueAsString(schema));
}
public static class IntegerSchema {
#JsonProperty
String type;
#JsonProperty
double min;
#JsonProperty
#JsonSerialize(using=MyDoubleDesirializer.class)
double max;
}
public static class MyDoubleDesirializer extends JsonSerializer<Double> {
#Override
public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
// TODO Auto-generated method stub
BigDecimal d = new BigDecimal(value);
gen.writeNumber(d.toPlainString());
}
}
}
The trick is to register a custom Serializer for your Double value. This way, you can control what you want.
I am using the BigDecimal value to create a String representation of your Double. The output then becomes (for the specific example):
{"type":"Int","min":100.0,"max":10200000000}
I hope that solves your problem.
Artur
Feature.WRITE_BIGDECIMAL_AS_PLAIN
set this for your Object Mapper
I know I am answering late, but something I faced may help other
While converting a BigDecimal I have faced below is working
mapper = mapper.setNodeFactory(JsonNodeFactory.withExactBigDecimals(true));
while this is not working for me
mapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
Update for Jakson 2.9.10:
Property WRITE_BIGDECIMAL_AS_PLAIN replaced to com.fasterxml.jackson.core.JsonGenerator. You could use:
mapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
If you are using ValueToTree then no need of any factory settings. only problem with ValueToTree is it is converting as TextNode (String Fromat), So if you have any logic based on ObjectNodes it will not work
You should use
mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
To avoid scientific notation on floating numbers.
You can find an example below.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
String test ="{\"doubleValue\" : 0.00001}";
try {
System.out.println(mapper.readTree(test).toPrettyString());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
Output
{
"doubleValue" : 0.00001
}

Creating JSON without quotes

A library is using Map to use some extra information. This map eventually is being converted a JSON object and I need to set request information to display for debugging purposes as this:
map.put("request", requestString);
I am considering to use Jackson specifically to create a JSON without quotes and want to set as requestString.
I am building necessary information regarding Request and building a Map including request headers, parameters, method etc.
Jackson is creating perfectly valid JSON with quotes but when I set this generated value inside map, It is displayed ugly because of having escaped quotes.
So Jackson is creating this:
{
method : "POST",
path : "/register"
}
When I set this in map, it turns to this:
{
method : \"POST\",
path : \"/register\"
}
Consider this as a huge map including all parameters and other information about request.
What I would like to want this:
{
method : POST,
path : /register
}
I know that this is not a valid JSON but I am using this as a String to a Map which is accepting String values.
public class UnQuotesSerializer extends NonTypedScalarSerializerBase<String>
{
public UnQuotesSerializer() { super(String.class); }
/**
* For Strings, both null and Empty String qualify for emptiness.
*/
#Override
public boolean isEmpty(String value) {
return (value == null) || (value.length() == 0);
}
#Override
public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeRawValue(value);
}
#Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
return createSchemaNode("string", true);
}
#Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
if (visitor != null) visitor.expectStringFormat(typeHint);
}
}
and
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule("UnQuote");
module.addSerializer(new UnQuotesSerializer());
objectMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
objectMapper.registerModule(module);
This is generating without quotes strings.
The following test passes (Jackson 2.5.0)
#Test
public void test() throws Exception {
ObjectMapper mapper = new ObjectMapper();
Map map = new HashMap();
map.put("method", "POST");
map.put("request", "/register");
String s = mapper.writeValueAsString(map);
Map map2 = mapper.readValue(s, Map.class);
Assert.assertEquals(map, map2);
}
so your pseudo JSON without quotes does not seem the way to go

Spring Batch JdbcBatchItemWriter setSql never throws exception

My simple flow of batch process reads from a CSV file and write into a MySQL database (batch configuration is ok and works).
I'm using a custom implementation of JdbcBatchItemWriter in order to do the job and I'm actually making an Update in my writer constructor.
CsvReader.java
#Component
#StepScope
public class EducationCsvReader extends FlatFileItemReader {
public final static String CSV_FILE_NAME = "education.csv.file";
#Value("#{jobParameters['"+ CSV_FILE_NAME +"']}")
public void setResource(final String csvFileName) throws Exception {
setResource(
new FileSystemResource(csvFileName)
);
}
public EducationCsvReader() {
setLinesToSkip(1);
setEncoding("UTF-8");
setStrict(true);
setLineMapper((line, num) -> {
String[] values = line.split(";");
return new Education()
.setName(values[2].trim())
.setId(Integer.parseInt(values[0].trim()));
});
}
}
my custom JdbcBatchItemWriter : AbstractJdbcBatchItemWriter.java
public abstract class AbstractJdbcBatchItemWriter<T> extends JdbcBatchItemWriter<T>{
#Autowired
public AbstractJdbcBatchItemWriter(String SQL_QUERY) {
setSql(SQL_QUERY);
}
#Autowired
#Override
public void setItemSqlParameterSourceProvider(
#Qualifier("beanPropertyItemSqlParameterSourceProvider") ItemSqlParameterSourceProvider provider){
super.setItemSqlParameterSourceProvider(provider);
}
#Autowired
#Override
public void setDataSource(#Qualifier("mysqlDataSource") DataSource dataSource){
super.setDataSource(dataSource);
}
}
And here is my writer implementation : MySQLWriter.java
#Component
public class EducationMysqlWriter extends AbstractJdbcBatchItemWriter<Education> {
public EducationMysqlWriter(){
super("");
try {
setSql("UPDATE ecole SET nom=:name WHERE id=:id");
} catch (EmptyResultDataAccessException exception){
setSql("INSERT INTO ecole (nom, id) VALUES (:name, :id");
}
}
}
I need to update rows but if it fails (EmptyResultDataAccessException) I need to do an Insert.
But EmptyResultDataAccessException is shown on log console and kills the job but the exception catching is never reachable into MySQLWriter.java ...
JdbcBatchItemWriter#setSql doesn't throw an exception because it doesn't do anything but assign a string to an instance variable. The try block in the constructor doesn't have anything to do with the write method, it is executed when the itemwriter is first instantiated, while the write method is executed once for each chunk of items being processed. If you read the stacktrace I expect you'll see the JdbcBatchtemWriter is executing its write method and throwing the exception.
The ItemWriter is not going to get instantiated for each row so, assuming you will have some rows that need to be inserted and some that need to be updated, setting the sql string in the constructor does not seem like a good idea.
You could override the ItemWriter#write method, using a separate sql string for the insert, but it would be easier to use one string using the mysql upsert syntax:
INSERT INTO ecol (nom, id) VALUES (:name, :id)
ON DUPLICATE KEY UPDATE nom = :name;

How JAXB/Jersey unmarshall Boolean values?

I have an issue with some RESTful services that takes a transfer object in parameter (basically an XML object that will be unmarshalled to a POJO).
#XmlRootElement(name = "myPojo")
public class MyPojo {
#XmlElement(name = "myField")
private Boolean myBoolean;
public void setMyBoolean(Boolean bool) {
myBoolean = bool;
}
public Boolean getMyBoolean() {
return myBoolean;
}
}
And the service is something like that:
public class MyRestService {
#PUT
#Path("somewhere")
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response update(MyPojo pojo) {
System.out.println("Boolean value: " + pojo.getMyBoolean();
}
}
If I post this XML fragment:
<myPojo>
<myField>false</myField>
</myPojo>
I got:
Boolean value: false
And if I post this XML fragment:
<myPojo>
<myField>FALSE</myField>
</myPojo>
I got:
Boolean value: null
I run that code under Glassfish 4 with Jersey 1.9.1 and JAXB 2.2.7. In addition, under Glassfish 2, I got a different behavior where both uppercase and lowercase are unmarshalled as expected.
So, I am really curious to know what is happening and why the marshalling of boolean is different.
Thanks in advance
I run into the same problem today where JAXB returns null when parsing "FaLsE" or "True" on a Boolean field. Unfortunately, upgrading to 2.2.7 or above (2.2.11 as of today) didn't help me. When I dig deeper into the source code, it seems that the parsing logic happens inside DatatypeConverterImpl.java. And there is no configuration that can alter its behavior on uppercase.
Link to JAXB DatatypeConverterImpl.java
The solution that I found (and works), is to define a new BooleanAdapter and asks JAXB to use that instead. In the adapter, you can define whatever conversion logic that fits your application.
Custom BooleanAdapter.java
public class BooleanAdapter extends XmlAdapter<String, Boolean> {
#Override
public Boolean unmarshal(String v) throws Exception {
if (StringUtils.isBlank(v))
return null;
return Boolean.valueOf(v);
}
#Override
public String marshal(Boolean v) throws Exception {
if (v == null)
return null;
return v.toString();
}
}
Your model object
#XmlElement(name = "myField")
#XmlJavaTypeAdapter(BooleanAdapter.class)
public Boolean getMyBoolean() {
return myBoolean;
}
After several investigations, we figured out that the version 2.2 of JAXB we are using seems to contain a bug that serialize the boolean values not as expected. I mean that for example: FaLsE will be converted to null value.
Upgrading to the version 2.2.7 has fixed our issue.