master
Harald Wolff 2017-11-23 13:05:58 +01:00
parent 659088b90e
commit b65cfd952e
13 changed files with 660 additions and 166 deletions

View File

@ -0,0 +1,45 @@
using System;
using System.IO;
namespace sharp.json
{
public class FileBackedJSONValue<T>
{
public string FileName { get; set; }
public DateTime LoadedWriteTime { get; set; }
T current;
JSON jsource;
public FileBackedJSONValue(string filename)
{
FileName = filename;
}
public T CurrentValue {
get
{
if (!File.Exists(FileName)){
current = default(T);
} else if ((current == null) || (File.GetLastWriteTime(FileName) != LoadedWriteTime))
{
jsource = JSON.ReadFrom(FileName);
LoadedWriteTime = File.GetLastWriteTime(FileName);
current = jsource.To<T>();
}
return current;
}
set
{
current = value;
Save();
}
}
public void Save(){
JSONConverter.From(current).WriteTo(FileName,true);
LoadedWriteTime = File.GetLastWriteTime(FileName);
}
}
}

232
JSON.cs
View File

@ -6,6 +6,8 @@ using System.Net;
using System.Reflection;
using System.Collections;
using System.Security.Cryptography;
using System.CodeDom;
using System.Globalization;
namespace sharp.json
{
@ -17,6 +19,7 @@ namespace sharp.json
public virtual long Integer { get { throw new NotImplementedException(); } }
public virtual string String { get { throw new NotImplementedException(); } }
public virtual bool Boolean { get { throw new NotImplementedException(); } }
public virtual object Object { get { throw new NotImplementedException(); } }
public virtual JSON this[int n]
{
@ -78,142 +81,108 @@ namespace sharp.json
return b ? JSONSpecial.True : JSONSpecial.False;
}
public T To<T>(){
object o = Create(typeof(T));
return (T)o;
public static implicit operator string(JSON json)
{
return json.String;
}
public static implicit operator bool(JSON json)
{
return json.Boolean;
}
public static implicit operator int(JSON json)
{
return (int)json.Integer;
}
public static implicit operator long(JSON json)
{
return json.Integer;
}
public static implicit operator double(JSON json)
{
return json.Double;
}
public void WriteTo(Stream stream){
byte[] data = Encoding.ASCII.GetBytes(ToString());
public T To<T>()
{
return JSONConverter.To<T>(this);
}
public static JSON From(object o){
return JSONConverter.From(o);
}
public void WriteTo(Stream stream)
{
WriteTo(stream);
}
public void WriteTo(Stream stream,bool pretty){
byte[] data = Encoding.ASCII.GetBytes(pretty ? prettyFormat() : ToString() );
stream.Write(data,0,data.Length);
}
public void WriteTo(String filename)
{
WriteTo(filename, false);
}
public void WriteTo(String filename,bool pretty)
{
FileStream fs = new FileStream(filename, FileMode.Create);
WriteTo(fs);
WriteTo(fs,pretty);
fs.Close();
}
public static JSON ReadFrom(string filename){
public static JSON ReadFrom(string filename)
{
return ReadFrom(filename, null);
}
public static JSON ReadFrom(string filename, object defaultValue)
{
JSONParser parser = new JSONParser();
string source = File.ReadAllText(filename);
string source = "";
try
{
source = File.ReadAllText(filename);
}
catch (FileNotFoundException e)
{
return JSON.From(defaultValue);
}
return parser.Parse(source);
}
private object Create(Type t)
{
if (t.IsPrimitive || (t == typeof(string)) )
public static JSON ReadFrom(string filename,JSON defaultValue){
JSONParser parser = new JSONParser();
string source = "";
try
{
return CreatePrimitive(t);
source = File.ReadAllText(filename);
} catch (FileNotFoundException e){
return defaultValue;
}
if (this.JSONType == JSONTypes.Object)
{
return CreateObject(t);
}
if ((this.JSONType == JSONTypes.Array) && (t.IsArray))
{
return CreateArray(t);
}
throw new InvalidCastException(String.Format("JSON {0} can't be casted to {1}", this.JSONType.ToString(), t.Name));
return parser.Parse(source);
}
private object CreatePrimitive(Type t){
if ((this.JSONType == JSONTypes.Null)){
return null;
}
if ((this.JSONType == JSONTypes.Array) || (this.JSONType == JSONTypes.Object)){
throw new InvalidCastException(String.Format("JSON {0} can't be casted to {1}",this.JSONType.ToString(),t.Name));
}
if (t.Equals(typeof(int)) || t.Equals(typeof(long)) || t.Equals(typeof(short))){
return (object)this.Integer;
}
if (t.Equals(typeof(double)) || t.Equals(typeof(float)))
public object Native(){
switch (JSONType)
{
return (object)this.Double;
case JSONTypes.Null:
return null;
case JSONTypes.True:
return true;
case JSONTypes.False:
return false;
case JSONTypes.Number:
return Double;
case JSONTypes.String:
return String;
}
if (t.Equals(typeof(string)))
{
return (object)this.String;
}
if (t.Equals(typeof(Boolean)))
{
return (object)this.Boolean;
}
throw new Exception(String.Format("Unsupported primitive type",t.Name));
throw new InvalidCastException(String.Format("Can't create native type of {0}",this.JSONType));
}
private object CreateObject(Type t){
if (t.GetConstructor(new Type[] { typeof(JSON) } ) != null){
return Activator.CreateInstance(t, this);
}
object instance = Activator.CreateInstance(t);
Dictionary<string, FieldPropertyInfo> assignedFields = new Dictionary<string, FieldPropertyInfo>();
foreach (FieldInfo fi in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
foreach (JSONField f in fi.GetCustomAttributes<JSONField>())
{
if (this.Contains(f.Alias))
{
if (!assignedFields.ContainsKey(f.Alias) || assignedFields[f.Alias].IsAutoAssigned){
assignedFields[f.Alias] = new FieldPropertyInfo(fi, false);
break;
}
}
}
if (!assignedFields.ContainsKey(fi.Name) && this.Contains(fi.Name)){
assignedFields[fi.Name] = new FieldPropertyInfo(fi, true);
}
}
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
foreach (JSONField f in pi.GetCustomAttributes<JSONField>())
{
if (this.Contains(f.Alias))
{
if (!assignedFields.ContainsKey(f.Alias) || assignedFields[f.Alias].IsAutoAssigned)
{
assignedFields[f.Alias] = new FieldPropertyInfo(pi, false);
break;
}
}
}
if (!assignedFields.ContainsKey(pi.Name) && this.Contains(pi.Name))
{
assignedFields[pi.Name] = new FieldPropertyInfo(pi, true);
}
}
foreach (KeyValuePair<string,FieldPropertyInfo> e in assignedFields){
e.Value.setValue(instance, this[e.Key].Create(e.Value.ValueType));
}
return instance;
}
private object CreateArray(Type t)
{
Array a = Array.CreateInstance(t.GetElementType(), this.Count);
for (int n = 0; n < this.Count;n++){
a.SetValue(this[n].Create(t.GetElementType()),n);
}
return a;
}
public virtual IEnumerator<JSON> GetEnumerator()
{
throw new NotImplementedException();
@ -223,46 +192,5 @@ namespace sharp.json
{
return (IEnumerator)GetEnumerator();
}
struct FieldPropertyInfo {
public bool IsAutoAssigned { get; set; }
FieldInfo FieldInfo { get; set; }
PropertyInfo PropertyInfo { get; set; }
public FieldPropertyInfo(PropertyInfo propertyInfo,bool autoAssigned)
{
this.IsAutoAssigned = autoAssigned;
this.PropertyInfo = propertyInfo;
this.FieldInfo = null;
}
public FieldPropertyInfo(FieldInfo fieldInfo,bool autoAssigned)
{
this.IsAutoAssigned = autoAssigned;
this.PropertyInfo = null;
this.FieldInfo = fieldInfo;
}
public void setValue(object inst,object value){
if (PropertyInfo != null){
PropertyInfo.SetValue(inst,value);
} else if (FieldInfo != null){
FieldInfo.SetValue(inst,value);
}
}
public Type ValueType {
get {
if (PropertyInfo != null){
return PropertyInfo.PropertyType;
} else if (FieldInfo != null){
return FieldInfo.FieldType;
}
return null;
}
}
}
}
}

View File

@ -9,6 +9,16 @@ namespace sharp.json
public JSONArray()
: base(JSONTypes.Array) { }
public JSONArray(object[] init)
: base(JSONTypes.Array)
{
foreach (object o in init)
{
this.values.Add(JSONConverter.From(o));
}
}
List<JSON> values = new List<JSON>();
public override bool Boolean

350
JSONConverter.cs 100644
View File

@ -0,0 +1,350 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using sharp.json.attributes;
using System.Reflection;
using sharp.extensions;
namespace sharp.json
{
public static class JSONConverter
{
delegate object ConvertToDelegate(Type t,JSON json);
static Dictionary<Type, ConvertToDelegate> toDelegates = new Dictionary<Type, ConvertToDelegate>{
{ typeof(string), (t, json) => json.String },
{ typeof(int), (t, json) => json.Integer },
{ typeof(short), (t, json) => json.Integer },
{ typeof(long), (t, json) => json.Integer },
{ typeof(uint), (t, json) => json.Integer },
{ typeof(ushort), (t, json) => json.Integer },
{ typeof(ulong), (t, json) => json.Integer },
{ typeof(double), (t, json) => json.Double },
{ typeof(float), (t, json) => json.Double },
{ typeof(bool), (t, json) => json.Boolean },
{ typeof(DateTime), (t, json) => DateTime.Parse(json.String, CultureInfo.InvariantCulture) },
{ typeof(Guid), (t, json) => Guid.Parse(json.String)},
{ typeof(object), ToObject }
};
public static T To<T>(JSON json)
{
Type t = typeof(T);
return (T)(object)To(t, json);
}
public static JSON From(object value)
{
if (value == null)
{
return JSONSpecial.Null;
}
return From(value.GetType(), value);
}
public static object To(Type t,JSON json){
if (json.JSONType == JSONTypes.Null){
return null;
}
if (t.IsEnum){
return Enum.Parse(t, json.String);
}
if (toDelegates.ContainsKey(t))
{
return toDelegates[t](t, json);
}
if (t.IsArray){
return ToArray(t, json);
}
if (!t.IsPrimitive){
return ToObject(t, json);
}
throw new InvalidCastException(String.Format("JSON {0} can't be casted to {1}", json.JSONType.ToString(), t.Name));
}
public static void ApplyObject(JSON json, object o)
{
FieldPropertyInfo[] fpilist = fpi(o.GetType());
foreach (FieldPropertyInfo fpi in fpilist)
{
if (json.Contains(fpi.Key))
{
fpi.setValue(o, To(fpi.ValueType, json[fpi.Key]));
}
}
}
public static object ToObject(Type t,JSON json){
ConstructorInfo ci = t.GetConstructor(new Type[] { typeof(JSON) });
if (ci != null)
{
if (ci.GetParameters()[0].ParameterType.Equals(typeof(JSON)))
{
return Activator.CreateInstance(t, (object)json);
}
}
JSONClassPolicy cp = t.GetCustomAttribute<JSONClassPolicy>();
if (cp == null)
{
cp = new JSONClassPolicy();
}
return ToObject(t, json, cp.Policy);
}
private static object ToObject(Type t, JSON json,JSONPolicy policy)
{
object oi = Activator.CreateInstance(t);
ApplyObject(json,oi);
return oi;
}
private static object ToArray(Type t,JSON json)
{
Array a = Array.CreateInstance(t.GetElementType(), json.Count);
for (int n = 0; n < json.Count; n++)
{
a.SetValue(To(t.GetElementType(),json[n]), n);
}
return a;
}
public static JSON From(Type t, object value)
{
if (value == null)
{
return JSONSpecial.Null;
}
if (t == null)
{
t = value.GetType();
}
if ((t.IsPrimitive) || (t == typeof(string)))
{
return FromPrimitive(value);
}
if (t == typeof(DateTime))
{
return new JSONString(((DateTime)value).ToString(CultureInfo.InvariantCulture));
}
if (t == typeof(Guid))
{
return ((Guid)value).ToString();
}
if (t.IsEnum)
{
return new JSONString(value.ToString());
}
if (t.IsArray)
{
JSONArray ja = new JSONArray();
Array a = (Array)value;
Type et = t.GetElementType();
if (et == typeof(object))
{
et = null;
}
foreach (object e in a)
{
ja.Add(From(et, e));
}
return ja;
}
return FromObject(value);
}
public static JSON FromPrimitive(object value)
{
Type t = value.GetType();
if (typeof(int).Equals(t))
{
return new JSONNumber((int)value);
}
if (typeof(long).Equals(t))
{
return new JSONNumber((long)value);
}
if (typeof(double).Equals(t))
{
return new JSONNumber((double)value);
}
if (typeof(float).Equals(t))
{
return new JSONNumber((float)value);
}
if (typeof(string).Equals(t))
{
return new JSONString(value.ToString());
}
if (typeof(bool).Equals(t))
{
return ((bool)value) ? JSONSpecial.True : JSONSpecial.False;
}
throw new NotImplementedException(String.Format("Cast of {0} to JSON is not (yet) supported", t.Name));
}
public static JSON FromObject(object value)
{
return FromObject(value.GetType(), value);
}
public static JSON FromObject(Type type, object value)
{
Type t = value.GetType();
JSONObject jo = new JSONObject();
foreach (FieldPropertyInfo fpi in fpi(t)){
jo[fpi.Key] = JSON.From(fpi.getValue(value));
}
return jo;
}
private static FieldPropertyInfo[] fpi(Type t)
{
JSONClassPolicy cp = t.GetCustomAttribute<JSONClassPolicy>();
if (cp == null)
{
cp = new JSONClassPolicy();
}
return fpi(t, cp);
}
private static FieldPropertyInfo[] fpi(Type t,JSONClassPolicy cp)
{
BindingFlags bf;
switch (cp.Policy){
case JSONPolicy.ALL:
bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
break;
case JSONPolicy.ATTRIBUTED:
bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
break;
case JSONPolicy.NONPUBLIC:
bf = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
break;
default:
bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
break;
}
List<FieldPropertyInfo> fpilist = new List<FieldPropertyInfo>();
foreach (FieldInfo fi in t.GetFields(bf))
{
fpilist.Add(new FieldPropertyInfo(fi));
}
foreach (PropertyInfo pi in t.GetProperties(bf))
{
fpilist.Add(new FieldPropertyInfo(pi));
}
FieldPropertyInfo[] temp = fpilist.ToArray();
fpilist.Clear();
foreach (FieldPropertyInfo fpi in temp){
if ((cp.Policy != JSONPolicy.ATTRIBUTED) || (fpi.JSONField != null))
{
fpilist.Add(fpi);
}
}
if (!t.BaseType.IsNull()){
fpilist.AddRange(fpi(t.BaseType,cp));
}
return fpilist.ToArray();
}
struct FieldPropertyInfo
{
public String Key { get; set; }
FieldInfo FieldInfo { get; set; }
PropertyInfo PropertyInfo { get; set; }
public JSONField JSONField { get; set; }
public FieldPropertyInfo(PropertyInfo propertyInfo)
{
this.PropertyInfo = propertyInfo;
this.FieldInfo = null;
this.JSONField = propertyInfo.GetCustomAttribute<JSONField>();
this.Key = (this.JSONField == null) ? propertyInfo.Name : ((this.JSONField.Alias == null) ? propertyInfo.Name : this.JSONField.Alias);
}
public FieldPropertyInfo(FieldInfo fieldInfo)
{
this.PropertyInfo = null;
this.FieldInfo = fieldInfo;
this.JSONField = fieldInfo.GetCustomAttribute<JSONField>();
this.Key = (this.JSONField == null) ? fieldInfo.Name : ((this.JSONField.Alias == null) ? fieldInfo.Name : this.JSONField.Alias);
}
public void setValue(object inst, object value)
{
if (PropertyInfo != null)
{
PropertyInfo.SetValue(inst, value);
}
else if (FieldInfo != null)
{
FieldInfo.SetValue(inst, value);
}
}
public object getValue(object inst)
{
if ((PropertyInfo != null)&&(!PropertyInfo.GetMethod.IsNull()))
{
return PropertyInfo.GetValue(inst);
}
else if (FieldInfo != null)
{
return FieldInfo.GetValue(inst);
}
return null;
}
public Type ValueType
{
get
{
if (PropertyInfo != null)
{
return PropertyInfo.PropertyType;
}
else if (FieldInfo != null)
{
return FieldInfo.FieldType;
}
return null;
}
}
}
}
}

View File

@ -71,7 +71,7 @@ namespace sharp.json
for (int n=0;n<keys.Length;n++)
{
sb.Append(new JSONString(keys[n]));
sb.Append(new JSONString(keys[n]).ToString());
sb.Append(":");
sb.Append(this[keys[n]].ToString());
if (n+1 < keys.Length){

View File

@ -281,6 +281,7 @@ namespace sharp.json
LexerPathSegment digit_c = new LexerPathSegment(CharGroup.digit,true);
LexerPathSegment dot = new LexerPathSegment('.');
LexerPathSegment ee = new LexerPathSegment(eE);
LexerPathSegment eminus = new LexerPathSegment(CharGroup.minus);
LexerPathSegment plusminus = new LexerPathSegment(CharGroup.plusminus);
head.AddFollower(minus);
@ -309,6 +310,8 @@ namespace sharp.json
ee.AddFollower(digit_c);
ee.AddFollower(plusminus);
plusminus.AddFollower(digit_c);
digit_c.AddFollower(digit_c);
return head;

View File

@ -37,7 +37,17 @@ namespace sharp.json
}
HttpResponse response = req.Send();
return jsonParser.Parse(response.ContentText);
try {
return jsonParser.Parse(response.ContentText);
} catch (Exception e){
Console.WriteLine("JSONWebRequest could not parse response.");
Console.WriteLine("Response was:");
Console.WriteLine(">-------------------------------------------");
Console.WriteLine(response.ContentText);
Console.WriteLine("<-------------------------------------------");
throw e;
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace sharp.json.attributes
{
public enum JSONPolicy { ALL, PUBLIC, NONPUBLIC, ATTRIBUTED }
public class JSONClassPolicy : Attribute
{
public JSONPolicy Policy { get; set; } = JSONPolicy.PUBLIC;
}
}

View File

@ -1,6 +1,6 @@
using System;
namespace sharp.json
namespace sharp.json.attributes
{
public class JSONField : Attribute
{

View File

@ -17,21 +17,25 @@ namespace json.test
public static void Main(string[] args)
{
JSON json;
JSONParser jsonparser = new JSONParser();
Console.WriteLine("JSON test Patterns:");
Console.WriteLine();
json = jsonparser.Parse("4.9125E-05");
Console.WriteLine(json.ToString());
foreach (string src in sources){
json = jsonparser.Parse(src);
Console.WriteLine("NEW PARSER: {0}",json.ToString());
}
//Console.WriteLine("JSON test Patterns:");
//Console.WriteLine();
json = jsonparser.Parse(File.ReadAllText("test.json"));
Console.WriteLine("");
Console.WriteLine("test.json file:");
Console.WriteLine("PARSED: {0}",json.ToString());
//foreach (string src in sources){
// json = jsonparser.Parse(src);
// Console.WriteLine("NEW PARSER: {0}",json.ToString());
//}
//json = jsonparser.Parse(File.ReadAllText("test.json"));
//Console.WriteLine("");
//Console.WriteLine("test.json file:");
//Console.WriteLine("PARSED: {0}",json.ToString());
}

View File

@ -0,0 +1,51 @@
using System;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace sharp.json.network
{
public class JSONTcpClient
{
TcpClient client;
StreamReader reader;
StreamWriter writer;
JSONParser parser = new JSONParser();
public JSONTcpClient(int port)
{
this.client = new TcpClient();
this.client.Connect("127.0.0.1",port);
this.initialize();
}
public JSONTcpClient(TcpClient client)
{
this.client = client;
initialize();
}
private void initialize(){
this.reader = new StreamReader(client.GetStream());
this.writer = new StreamWriter(client.GetStream());
}
public JSON Receive()
{
string line = reader.ReadLine();
JSON json = parser.Parse(line);
return json;
}
public void Send(JSON json){
writer.WriteLine(json.ToString());
writer.Flush();
}
public void Close(){
this.client.Close();
}
}
}

View File

@ -0,0 +1,74 @@
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace sharp.json.network
{
public delegate void JSONClientConnected(JSONTcpClient jsonClient);
public class JSONTcpServer
{
public JSONClientConnected ClientConnected { get; set; }
TcpListener listener;
Thread serverThread;
bool shouldExit;
public JSONTcpServer(int port)
{
this.listener = new TcpListener(IPAddress.Loopback, port);
}
public void Start()
{
lock (this){
if (serverThread == null){
serverThread = new Thread(Serve);
serverThread.Start();
}
}
}
public void Stop()
{
lock (this){
shouldExit = true;
this.listener.Stop();
Monitor.Wait(this);
this.serverThread = null;
}
}
public void Serve()
{
this.listener.Start();
while (true){
lock (this){
if (shouldExit){
shouldExit = false;
Monitor.Pulse(this);
break;
}
}
try {
TcpClient client = this.listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem((state) => fireClientConnected(client));
} catch (SocketException se){
}
}
}
private void fireClientConnected(TcpClient client){
if (ClientConnected != null){
JSONTcpClient jsonCLient = new JSONTcpClient(client);
ClientConnected.Invoke(jsonCLient);
}
}
}
}

View File

@ -42,7 +42,12 @@
<Compile Include="JSONWebRequest.cs" />
<Compile Include="JSONSerializer.cs" />
<Compile Include="JSONParser.cs" />
<Compile Include="JSONField.cs" />
<Compile Include="FileBackedJSONValue.cs" />
<Compile Include="network\JSONTcpServer.cs" />
<Compile Include="network\JSONTcpClient.cs" />
<Compile Include="attributes\JSONClassPolicy.cs" />
<Compile Include="attributes\JSONField.cs" />
<Compile Include="JSONConverter.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\sharp-extensions\sharp.extensions.csproj">
@ -62,6 +67,10 @@
<Name>sharp.contracts</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="network\" />
<Folder Include="attributes\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<MonoDevelop>