I'm using Thymeleaf with Spring Boot 2.
Is it possible to provide message sources (translations) in YAML / JSON format instead of *.properties files ?
yes, you can do it by extending the AbstractMessageSource class. here a sample you can use as a starting point:
#Component("messageSource")
public class JsonMessageSource extends AbstractMessageSource {
private static final String DEFAULT_LOCALE_CODE = "en";
#Override
protected MessageFormat resolveCode(String key, Locale locale) {
String message = resolveUsingJsonOrYaml(key,locale); //you have to implement this this
if (message == null) {
message = resolveUsingJsonOrYaml(key,DEFAULT_LOCALE_CODE);
}
return new MessageFormat(message, locale);
}
}
Related
We know that we can parse json file into IConfigurationRoot as
public class Startup
{
public IConfigurationRoot Configuration { get; }
public Startup(IHostingEnvironment env)
{
this.Configuration = new ConfigurationBuilder()
.SetBasePath(path)
.AddJsonFile("somefile.json")
.Build();
}
}
But I want to use ConfigurationBuilder to parse a json string so can access just like how it works with json file so that I can do:
string jsonString = XXX(); // external calls to get json
var config = new ConfigurationBuilder().AddJsonString(jsonString).Build();
string name = config["Student:Name"];
So does imaginal AddJsonString exists or is any third party library I need to use to achieve this?
P.S
I can't use JsonSerializer because the json payload has too many property therefore I can't create a POJO model class to be deserialized with, if there are only 3 or 4 property, then I can certainly do that, but 50 properties (that has nested properties) is a different story
You can use new ConfigurationBuilder().AddJsonStream(new MemoryStream(Encoding.ASCII.GetBytes(jsonString))).Build(); to load json from MemoryStream.
My test Code:
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
string jsonString = "{\"source\": \"test.com\", \"Time\":\"Feb 2019\" }"; // external calls to get json
var config = new ConfigurationBuilder().AddJsonStream(new MemoryStream(Encoding.ASCII.GetBytes(jsonString))).Build();
string name = config["source"];
}
Test Result(.Net Core 3.1):
This is with the Docusign Rest api. When I call ToJson() on an EnvelopeDefinition, it returns the correct info, but I would like it to not serialize the base64 array for when I am writing this out to a log file. I tried using the [JsonIgnore] directive, but that stopped the array from being serialized altogether. Do I need to override the Serialize method on this class or just create another method, something like ToJsonForLogging() and not serialize that array?
I have created an extension method that will work for you. You can call this extension method in your code as follows
string json = envelopeDefinition.ToJsonLog(logDocumentBase64:false)
I am copying the DocumentBase64 into a temporary List and then using .ToJson() function to log without the documentBase64 property.
public static class EnvelopeDefinitionExtensions
{
public static string ToJsonLog(this EnvelopeDefinition envDefinition, bool logDocumentBase64 = true)
{
if (logDocumentBase64) return envDefinition.ToJson();
var tempDocumentBase64List = new List<string>();
foreach(var doc in envDefinition.Documents)
{
tempDocumentBase64List.Add(doc.DocumentBase64);
doc.DocumentBase64 = null;
}
string json = envDefinition.ToJson();
int i =0;
foreach(var doc in envDefinition.Documents)
{
doc.DocumentBase64 = tempDocumentBase64List[i];
i++;
}
return json;
}
}
I am using Velocity Transformer email template with my Mule smtp. Is there any ways that I can add images in the email templates from my classpath ?
That is for example .. if I have an image say abc.png in my classpath, can I able to use it in my velocity email template like < image src= ......
You can add outbound attachments to the Mule Message, using classpath resources as their source. These Mule Message attachments will be turned into MIME parts by the SMTP outbound transformer.
From the discussion here Embedding images into html email with java mail it seems you need to declare the images like this:
<img src=\"cid:uniqueImageID\"/>
You have to use a unique ID after cid: that is consistent with the Content-ID part header. Mule allows you to specify custom part headers by adding an outbound message property java.util.Map named attachmentName+"Headers" (attachmentName is the name of the outbound attachment).
One potential difficulty is that the code in the ObjectToMimeMessage transformer that takes care of transforming a the javax.activation.DataHandler (coming from the Mule Message outbound attachment) in a javax.mail.BodyPart only calls setFileName but not setDisposition which I think is needed for the image to show properly. This said, I'm not an expert here, you probably know more about properly generating MIME emails with attached images.
1) Embed the image Base64 encoded in your HTML
e.g.
Use following site to convert image to base64:
http://www.dailycoding.com/Utils/Converter/ImageToBase64.aspx
I had followed your code to add image path in the velocity transformer in the following way, the String logo will get the value from spring beans
public final class MessageTransformer extends AbstractMessageTransformer
{
private VelocityEngine velocityEngine;
private String templateName;
private Template template;
//This part is for getting the value from property file by declaring setter and getter for fileName and subscriberName
private String logo;
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
//This part is for getting template for email from classpath configured in mule flow
public VelocityMessageTransformer()
{
registerSourceType(Object.class);
setReturnDataType(new SimpleDataType<String>(String.class));
}
public void setVelocityEngine(final VelocityEngine velocityEngine)
{
this.velocityEngine = velocityEngine;
}
public void setTemplateName(final String templateName)
{
this.templateName = templateName;
}
#Override
public void initialise() throws InitialisationException
{
try
{
template = velocityEngine.getTemplate(templateName);
}
catch (final Exception e)
{
throw new InitialisationException(e, this);
}
}
#Override
public Object transformMessage(final MuleMessage message, final String outputEncoding)throws TransformerException
{
try
{
final StringWriter result = new StringWriter();
FileDataSource myFile = new FileDataSource (new File (logo)); // It contains path of image file
message.setOutboundProperty("logo", myFile);
// -------------------------------------------------------
final Map<String, Object> context = new HashMap<String, Object>();
context.put("message", message);
context.put("payload", message.getPayload());
context.put("logo", message.getOutboundProperty("logo"));
template.merge(new VelocityContext(context), result); //Merging all the attributes
System.out.println("MAIL WITH TEMPLATE SEND SUCCESSFULLY !!!");
System.out.println( result.toString() );
return result.toString();
}
catch (final Exception e)
{
throw new TransformerException(
MessageFactory.createStaticMessage("Can not transform message with template: " + template)
, e);
}
}
}
I need to parse this json string to values.
"start": { "dateTime": "2013-02-02T15:00:00+05:30" }, "end": { "dateTime": "2013-02-02T16:00:00+05:30" },
The problem is I am using JSONParser in apex (salesforce).
And my class is:
public class wrapGoogleData{
public string summary{get;set;}
public string id{get;set;}
public string status;
public creator creator;
public start start;
public wrapGoogleData(string entnm,string ezid,string sta, creator c,start s){
summary= entnm;
id= ezid;
status = sta;
creator = c;
start = s;
}
}
public class creator{
public string email;
public string displayName;
public string self;
}
public class start{
public string datetimew;
}
I am able to get all the datat from this except the datetime in the above string. As datetime is a reserved keyword in apex so i am not able to give the variable name as datetime in my class.
Any suggestion !!
Json Parser code:
JSONParser parser = JSON.createParser(jsonData );
while (parser.nextToken() != null) {
// Start at the array of invoices.
if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
while (parser.nextToken() != null) {
// Advance to the start object marker to
// find next invoice statement object.
if (parser.getCurrentToken() == JSONToken.START_OBJECT) {
// Read entire invoice object, including its array of line items.
wrapGoogleData inv = (wrapGoogleData)parser.readValueAs(wrapGoogleData.class);
String s = JSON.serialize(inv);
system.debug('Serialized invoice: ' + s);
// Skip the child start array and start object markers.
//parser.skipChildren();
lstwrap.put(inv.id,inv);
}
}
}
}
Similar to Kumar's answer but without using an external app.
Changing your start class was the right idea
public class start{
public string datetimew;
}
Now, just parse the JSON before you run it through the deserializer.
string newjsondata = jsonData.replace('"dateTime"','"datetimew"');
JSONParser parser = JSON.createParser(newjsondata);
while (parser.nextToken() != null) {
...
}
Use string.replace() function and replace keys named dateTime with something like dateTime__x and then you can parse using Json.deserialize if you have converted your json to apex using json to apex convertor app on heruko platform
http://json2apex.herokuapp.com/
The above link points to an app that will convert Json into apex class and then you can use Json.serialize to parse json into apex class structure.
recently I have set up a WCF restful service with EF4.
It all worked out when returning XML format response. however when it comes to JSON, I got 504 Error. unable to return json data, WCF Resful Service .NET 4.0
By digging deeper by using Service Trace Viewer:
I found this error:
'The type 'xxx.DataEntity.AppView'
cannot be serialized to JSON because
its IsReference setting is 'True'. The
JSON format does not support
references because there is no
standardized format for representing
references. To enable serialization,
disable the IsReference setting on the
type or an appropriate parent class of
the type.'
The "AppView" is a complex object class which generated by EF4 from a store procedure.
I spend quite a bit time google how to disable the IsReference, very little result so far.
anyone? with any solutions?
thanks in advance
Code:
[OperationContract]
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "App/{id}/{format}")]
AppView FuncDetail(string id, string format);
public AppView FuncDetail(string id, string format)
{
SetResponseFormat(format);
return AppSvcs.GetById(id);
}
private void SetResponseFormat(string format)
{
if (format.ToLower() == "json")
{
ResponseContext.Format = WebMessageFormat.Json;
}
else
{
ResponseContext.Format = WebMessageFormat.Xml;
}
}
I ran into exactly the same issue. It only happened on one of my service methods where I was trying to return JSON serialised Entity objects. For all my other methods I was returning JSON serialised data transfer objects (DTOs), which are stand-alone and not connected to the Entity framework. I am using DTOs for data posted into methods. Often, the data you send out does not need all the data you store in the model or the database e.g. ID values, updated dates, etc. The mapping is done in the model class, like so:
public partial class Location
{
public static LocationDto CreateLocationDto(Location location)
{
LocationDto dto = new LocationDto
{
Accuracy = location.Accuracy,
Altitude = location.Altitude,
Bearing = location.Bearing
};
return dto;
}
It may seem a bit clunky but it works and it ensures that you only send the data fields you intended to send back. It works for me because I only have 5 or 6 entities but I can see that it would get a bit tedious if you have lots of classes.
I was running into the same problem, as caused by using the auto-generated ADO Entity Models. I have not found a direct fix for this issue, but as a work around, I serialize the response as json explicitly.
So in your example, the AppView FuncDetail looks like this:
public object FuncDetail(string id, string format)
{
SetResponseFormat(format);
// where AppSvc is the object type and the enumerable list of this type is returned by the GetById method, cast it to a json string
return JSONSerializer.ToJson<AppSvc>(AppSvcs.GetById(id));
}
Here are the Serializers that I'm using:
public static class GenericSerializer
{
public static DataTable ToDataTable<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null) return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition()
== typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
}
public static class JSONSerializer
{
public static string ToJson<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = GenericSerializer.ToDataTable(varlist);
return GetJSONString(dtReturn);
}
static object RowsToDictionary(this DataTable table)
{
var columns = table.Columns.Cast<DataColumn>().ToArray();
return table.Rows.Cast<DataRow>().Select(r => columns.ToDictionary(c => c.ColumnName, c => r[c]));
}
static Dictionary<string, object> ToDictionary(this DataTable table)
{
return new Dictionary<string, object>
{
{ table.TableName, table.RowsToDictionary() }
};
}
static Dictionary<string, object> ToDictionary(this DataSet data)
{
return data.Tables.Cast<DataTable>().ToDictionary(t => "Table", t => t.RowsToDictionary());
}
public static string GetJSONString(DataTable table)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(table.ToDictionary());
}
public static string GetJSONString(DataSet data)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(data.ToDictionary());
}}
It is a lot clearer to use Entity Metadata instead of Reflection.
The Metadata is pretty extensive.
another way to do this is to use LINQ to create an anonymous type with the subset of fields that you need from your entity and then use JSON.NET to serialize the collection of anon types that you created in the LINQ statement. then persist that collection out as a string by serializing.