I wrote a simple junit test. I want to test if I can write a java escaped backslash in front of a reference. This test fails and I dont know why.
Error Message: org.junit.ComparisonFailure: expected:<[\London]> but was:<[$branch]>
public class VelocityBackslashTest {
#Test
public void testVelocityBackslash() {
String inString = "\\$branch";
Velocity.init();
VelocityContext context = new VelocityContext();
context.put("branch", "London");
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "test_1", inString);
assertEquals("\\London", writer.toString());
}
}
If I do the same test but reading the template from a file. The result is positiv.
public class VelocityBackslashFileTest {
#Test
public void testVelocityBackslash() {
Properties p = new Properties();
p.setProperty("resource.loader", "classpath");
p.setProperty("classpath.resource.loader.class",
ClasspathResourceLoader.class.getName());
Velocity.init(p);
Template template =
Velocity.getTemplate("velocity/test_template.vm");
VelocityContext context = new VelocityContext();
context.put("branch", "London");
StringWriter writer = new StringWriter();
template.merge(context, writer);
assertEquals("\\London", writer.toString());
}
}
test_template.vm:
\\$branch
This is happening because of java.lang.String's use of \ as an escape character.
When you write
String inString = "\\$branch";
Java interprets the String literal \\ as an escaped backslash, so what is actually getting passed to Velocity is a single \ followed by $branch.
Velocity also uses \ as the escape character, so it interprets its input (\$branch) as a directive to escape the $ symbol. In other words, don't use it as Velocity markup simply print the literal $. Once this has happened then of course there is no attempt to resolve branch as a reference hence it is output as a literal.
To print \\ in front of a resolved Velocity reference, the Java String would need to pass 2 \ characters to Velocity, which would be done like this:
String inString = "\\\\$branch";
Related
We are using flutter easy localizations and we have texts that use arguments. So for example we have a string in our localizations doc like below,
{
"someAppText":"This is {} app text {}."
}
But sometimes the argument will be empty. Which will result in the following text
This is[SPACE][SPACE]app text[SPACE].
Where the spaces are still there. Is it possible to do a backspace whenever we have no arguments?
Firstly, what about using plural? Sounds like you want to have a different text for different kind of data. I do not come up with other examples when an arg will be empty, so if it is not your case could you please give a concrete example?
Secondly, you can do simple string manipulation as follows (pseudocode). The code only demonstrates the simplest case (to make it brief), but it is trivial to extend to the full case.
String myTranslate(String formatString, List<String> args) {
const EMPTY_MARKER = 'EMPTY_MARKER';
final transformedArgs = args.map((arg) => arg.isEmpty ? EMPTY_MARKER : arg).toList();
final rawString = formatString.tr(transformedArgs);
return rawString.replaceAll(' $EMPTY_MARKER', '');
}
Then in your example, it will output: This is[SPACE]app text.
we can not add any methods inside a JSON file, and only have to use it's simple map<String, String> data
so
a work around solution would use special strings inside the JSON to be able to detect and process them in run time
let's say JSON would have this
{
"someAppText": "This is #VAR01 app text #VAR02."
}
then let us create another class that has methods to handle these special words, they should detect them, and replace them with other dynamic inputs
so
class JSONWorkAround {
/// A - need to define the string pattern we are using in the string which I assumed to look like '#VAR00'
/// let's call them jsonVariables
/// NOTE : if you would like to name them #VAR000 ,, then regExp would be r'#VAR...'
static RegExp regExp = RegExp(r'#VAR..');
/// B - let's make a tracker for any word that matches this regExp in any input string
static List<String> _searchJSONVariablesByRegExp({#required String text, #required RegExp regExp}){
List<String> _strings;
/// always check if not null before we do stuff to avoid errors and save performance
if (text != null){
_strings = regExp.allMatches(text).map((m) => m.group(0)).toList();
}
return _strings;
}
/// C - let's make the tracker specifically for those JSONVariables from a string received from the JSON doc "let's call it rawString"
static List<String> _searchJSONVariablesFromRawString({#required String rawString}){
final List<String> _jsonVariables = _searchJSONVariablesByRegExp(text: rawString, regExp: regExp);
return _jsonVariables;
}
/// E - let's see what to do with the search result
static List<SpecialWord> _processJSONVariables(List<String> jsonVariables){
List<SpecialWord> _outputSpecialWords = <SpecialWord>[];
/// so w notice we will need to process each one alone,, so we loop them out
if(jsonVariables != null && jsonVariables.isNotEmpty){
jsonVariables.forEach((jsonVariable) {
/// we should receive a substitute string instead of that #VAR00 special string,, so ..
/// actually we need to receive a string that is accompanied with its cipher special thing to be able to go back to the sentence and change it,,, like using this special #VAR00 thing as ID
/// and I don't like map<String, dynamic> but I would rather create a model class ,, will be written down there at the end of this class
final SpecialWord _substitute = _processSingleJSONVariable(jsonVariable: jsonVariable);
/// then we add them to the output List
if (_substitute != null){
_outputSpecialWords.add(_substitute);
}
});
}
return _outputSpecialWords;
}
/// D - need to receive both the substitute and its (JSONSpecialVariable / ID) to be able to search for it and process it in the original string
static SpecialWord _processSingleJSONVariable({#required String jsonVariable}){
final SpecialWord _substitute = SpecialWord.getSpecialWordFromAllSpecialWordsByID(jsonVariable);
return _substitute;
}
/// F - finally after receiving the substitutes inside a list<SpecialWord>,, we get get back the original String with the substitutes
static String processJSONStringThatContainsThoseSpecialVariables(String rawString){
/// this has to initialize with the initial raw string value to be processed
String _processedString = rawString;
final List<String> _jsonVariables = _searchJSONVariablesFromRawString(rawString: rawString);
if (_jsonVariables != null && _jsonVariables.isNotEmpty){
final List<SpecialWord> _specialWords = _processJSONVariables(_jsonVariables);
/// then we need to change each jsonVariable with its substitute
_specialWords.forEach((specialWord) {
_processedString = _replaceSubStringWith(
subStringToReplace: specialWord.id,
replacement: specialWord.substitute,
input: _processedString,
);
});
}
return _processedString;
}
/// G - a text replacing method to easily replace a given subString from a string with another value
static String _replaceSubStringWith({#required String subStringToReplace, #required String replacement, #required String input}){
final String _output = input.replaceAll(subStringToReplace, replacement);
return _output;
}
}
class SpecialWord{
final String id;
final String substitute; // you can change this to be more complex to adapt to many languages or other things
const SpecialWord({
#required this.id,
#required this.substitute,
});
/// lets create a list of constants that u may change in future and call from db or wherever
static const List<SpecialWord> _allSpecialWords = const <SpecialWord>[
SpecialWord(id: '#VAR01', substitute: 'Baby'),
SpecialWord(id: '#VAR02', substitute: 'Cool'),
SpecialWord(id: '#VAR03', substitute: 'You got the Idea'),
];
/// I like to pamper myself with super quick methods to be clean and organized
static SpecialWord getSpecialWordFromAllSpecialWordsByID(String id){
SpecialWord _foundWord;
if (id != null){
_foundWord = _allSpecialWords.firstWhere((word) => word.id == id, orElse: () => null);
}
return _foundWord;
}
}
then lets make a little method test to assure the safety of this boiler plate over engineered code
test("Testing JSON Variables work around idea", () async {
String _rawString = "This is #VAR01 app text #VAR02.";
String _processedString = JSONWorkAround.processJSONStringThatContainsThoseSpecialVariables(_rawString);
String _expectation = "This is Baby app text Cool.";
expect(_processedString, _expectation);
});
But now you might ask yourself,, is it worth it,, did I over engineer things,, is there a wiser solution ?,, maybe just save each case in json from the start,, I don't know,,
I'm afraid I over complicated the solution,, but it works like a charm
I am not sure i understood your issue. But try the following.
Add two translations one for the empty argument someAppTextEmpty and one for the regular one someAppText
{
"someAppText": "This is {} app text {}.",
"someAppTextEmpty": "This is the alternative app text."
}
Then check if the argument is empty or not to get the right translation key:
final String translationKey = argument.isNotEmpty
? 'someAppText' : 'someAppTextEmpty';
Then pass the variable translationKey to the translation function of easy_localization like this:
final String title = tr(translationKey);
// Or
Text(translationKey).tr();
// Or
translationKey.tr();
No.
With or without easy_localization, the backspace character in Dart takes 1 space in a String instead of deleting 1 space. That is my conclusion through trial and error.
My suggestion:
Create a string called BACKSPACE with a never used value starting by a space eg:
final String BACKSPACE = 'NEVER_USED_VALUE';
When appropriate, assign BACKSPACE to value1 and value2 instead of an empty string.
Then, do this:
'someAppText'.tr(value1, value2).replaceAll(' ' + BACKSPACE, '');
Tl;dr: I want to get test MyCmdTest."data bind works" in this code green.
Thanks to Jeff Scott Brown for getting me that far.
I have a POGO with some custom conversions from JSON which I expect to receive in a Grails controller:
def myAction(MyCmd myData) {
...
}
With:
#Validateable
class MyCmd {
SomeType some
void setSome(Object value) {
this.some = customMap(value)
}
}
Note how customMap creates an instance of SomeType from a JSON value (say, a String). Let's assume the default setter won't work; for instance, an pattern we have around more than once is an enum like this:
enum SomeType {
Foo(17, "foos"),
Bar(19, "barista")
int id
String jsonName
SomeType(id, jsonName) {
this.id = id
this.jsonName = jsonName
}
}
Here, customMap would take an integer or string, and return the matching case (or null, if none fits).
Now, I have a unit test of the following form:
class RegistrationCmdTest extends Specification {
String validData // hard-coded, conforms to JSON schema
void test() {
MyCmd cmd = new MyCmd(JSON.parse(validData))
// check members: success
MyCmd cmd2 = JSON.parse(validData) as MyCmd
// check members: success
}
}
Apparently, setSome is called in both variants.
I also have a controller unit test that sets the request JSON to the same string:
void "register successfully"() {
given:
ResonseCmd = someMock()
when:
controller.request.method = 'POST'
controller.request.contentType = "application/json"
controller.request.json = validData
controller.myAction()
then:
noExceptionThrown()
// successful validations: service called, etc.
}
Basically the same thing also runs as integration test.
However, the mapping fails when running the full application; some == null.
Which methods do I have to implement or override so Grails calls my conversions (here, customMap) instead of inserting null where it doesn't know what to do?
It's possible to customize data binding using the #BindUsing annotation:
#BindUsing({ newCmd, jsonMap ->
customMap(jsonMap['someType'])
})
SomeType someType
See also the MWE repo.
Sources: Hubert Klein Ikkink # DZone, Official Docs (there are other ways to customize)
I have a unique requirement where i need to construct a JSON as below.
{
"XXXMonitoring/DC/EVN/DBNAME":{
"t":123456777,
"s":{
"CAPTURE":{
"c":100
}
}
}
}
where the root element "XXXMonitoring/DC/EVN/DBNAME" contains "/" in between as it represents a path. I tried with GSON to have nested java but not sure how i can represent "XXXMonitoring/DC/EVN/DBNAME" from my Java object.
Can someone help me on this.
I'm not sure if this is what are you asking...
But sollidus (/) is escaped by backslash (\) to be sure that the browser won’t mistake it for the closing script tag
when you need to use that key, you can remove backslash with String.replaceAll() method
json.toString().replaceAll("\\\\", "");
The JSON string can be constructed without POJO class using the below code.
If the JSON structure is same and only values will change for the keys, you can replace the hard coded values with variables and convert this into an utility method. The utility method can be reused to generate the JSON string.
public static void main(String[] args) throws IOException {
Gson gson = new Gson();
JsonObject jsonRootObject = new JsonObject();
JsonObject jsonFirstLevelObject = new JsonObject();
// t property
jsonFirstLevelObject.addProperty("t", 123456777);
JsonObject jsonCaptureObject = new JsonObject();
JsonObject jsonCObject = new JsonObject();
jsonCObject.addProperty("c", 100);
jsonCaptureObject.add("CAPTURE", jsonCObject);
// s property
jsonFirstLevelObject.add("s", jsonCaptureObject);
jsonRootObject.add("XXXMonitoring/DC/EVN/DBNAME", jsonFirstLevelObject);
System.out.println(gson.toJson(jsonRootObject));
}
I have a library called GsonPath which might suit your needs. The aim of the library is to provide an annotation processor that generates the boilerplate code to help simplify the POJO you need to write.
By using the library you can write a POJO similar to the following:
#AutoGsonAdapter(rootField = "XXXMonitoring/DC/EVN/DBNAME")
public class SamplePojo {
int t;
#SerializedName("s.CAPTURE.c")
int sCapture;
}
Then all you need to do in your gson object is to register a special TypeAdapterFactory
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapterFactory(GsonPath.createTypeAdapterFactory());
Gson gson = builder.create();
The documentation within the library is faily comprehensive, let me know if you have any problems!
I have an Json string return by facebook api and I want to cast it to an object, I tried using both Newton Json and JavaScriptSerializer.
https://graph.facebook.com/v1.0/1111111111111/comments?limit=25&after=NTA\u00253D
After I cast it to a strongly typed object or a dynamic object, the url will be changed to
https://graph.facebook.com/v1.0/1111111111111/comments?limit=25&after=NTA%3D
What is the cause of this issue?
I have tried url encoding and decoding, but it didn't work.
In JSON, any character can be represented by a unicode escape sequence, which is defined as \u followed by 4 hexadecimal digits (see JSON.org). When you deserialize the JSON, each escape sequence is replaced by the actual unicode character. You can see this for yourself if you run the following example program:
class Program
{
static void Main(string[] args)
{
string json = #"{ ""Test"" : ""\u0048\u0065\u006c\u006c\u006f"" }";
Foo foo = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(foo.Test);
}
}
class Foo
{
public string Test { get; set; }
}
Output:
Hello
In your example URL, \u0025 represents the % character. So the two URLs are actually equivalent. There is no issue here.
When a Json string contains 'key1:value1', this can be converted to the Dictionary type.
But in my case, it also contains an array of strings along with the above key:value, ie:
{k1:v1; "key2\":[{\"Key11\":{\"key21\":\"Val21\",\"key22\":\"val22\"}]
(The Json data contains some strings and some arrays.)
When I use Dictionary<string, string[]> or Dictionary<string, ArrayList> -- it is failing at the value as string - cannot convert string to string[], etc.
Still Dictionary<string, object> can be used, but is there any better way to handle this?
thanks
Phani
If you don't know the structure at compile-time, then there's no other way to serialize a JSON string-- it has to be Dictionary<string,object>. However, if you're using C# 4.0, you can use DynamicObject. Since dynamic typing defers type resolution until runtime, if you serialize using this approach, you can treat your serialized object as strongly-typed (albeit without compile-time support). That means you can use JSON-style dot notation to access properties:
MyDynamicJsonObject.key2
To accomplish this, you can inherit from DynamicObject, and implement the TryGetMember method (quoted from this link, which has a full implementation):
public class DynamicJsonObject : DynamicObject
{
private IDictionary<string, object> Dictionary { get; set; }
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
this.Dictionary = dictionary;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.Dictionary[binder.Name];
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return this.Dictionary.ContainsKey(binder.Name);
}
}
Note that dynamic typing currently doesn't support indexer notation, so for arrays, you'll need to implement a workaround using notation like this:
MyDynamicJsonObject.key2.Item(0)
Your example is not valid JSON, e.g. every key and value should be surrounded by ", e.g. {"k1":"v1"}, the number of opening and closing curly brackets must match, if you escape the " character by using \" you must add a another " character, e.g. "key2\""
Use a tool such as JSONLint to validate that your JSON is correct.