說不改了,可逃不過真香,此次是死也不改版git
把他這段話改一改,差很少就是個人心聲吧。github
『讓別人知道怎麼維護本身的權利作錯什麼了嗎?我辛辛苦苦維護了好一陣子的項目,開開心心發到網上給你們用,而後你幹啥了,躲在我不知道的地方 copy 項目,踩在我身上上架插件,到底誰作錯了?目前該揭露的都揭露了,該罵的也罵了,互不相欠!那都是便宜你了』json
我發現這人有個很奇怪的邏輯,一直在強調他作的比我好,就好像只要作得比我好了,他就什麼錯都沒有了。從一開始在 issue 中回覆我,到掘金裏的新項目預告,到新項目半成品出爐了以後的話,老是明裏暗裏說他作得怎麼怎麼好。數組
正常的開發者,只要腦殼正常,恐怕都幹不出這種 copy 別人代碼,而後隨便改點地方就做爲本身原創發佈到 github,甚至是 idea 官網這種事情,更不要提本身用小號給本身評分五星,還問我怎麼不想一想爲何我下載量比較少。難道以爲這件事情乾得很過度,我還反而是沒風度了?bash
我再重申一下個人觀點,開源項目你下載下來本身改沒什麼,可是你做爲原創再發布,甚至還拿去上架,這哪一個原創做者看到不心塞?想要對開源事業作貢獻,正確的作法是 fork 以後再改,改完還能夠提 pull request,這纔是真正在 github 上作貢獻的正確姿式,否則你改一個,他改一個,各自維護各自的,沒有一個輪子能作起來的。app
從一開始,我就沒期望給他的 issue 能起到什麼做用,事實上我也沒判斷錯。他面對被我抓了個現成這件事情,毫無愧疚感,也壓根不解釋爲何刪我註釋,在我不知情的狀況下自行發佈上架。他惟一提供的補償方式就是添加一個遲來的感謝連接,而後很委屈的表示『有時間重構就是了』。ide
對於這麼一我的,我還能說什麼呢?多說幾句我發現我脾氣也上來了,也快管不住本身嘴了。他好歹說了一句人話,那就是這事再鬧下去你們都浪費時間。可我想說的是,若是抄襲的人都像他這麼明目張膽死不認錯,被抄襲的人都忍氣吞聲,這纔是 TMD 有病吧?函數
好了,發泄夠了也就不會再更新了。工具
最後,但願你們發佈原創的時候記得加 LICENSE,這是對本身僅有的一點保障;也但願你們在用別人的代碼的時候,帶有一絲尊重。學習
那位老哥上傳了本身獨立完成的代碼,我去看了下代碼,作了一些花裏胡哨的封裝。並且在我作了測試以後感受他的項目徹底還不是能用的程度,bug 實在太多。固然,這麼短的時間想作出完成度高的東西,確實太難了,只是我真的好驚奇,他發東西出來懟我以前本身都不測試檢查一下的嗎?boolean 映射成了 num 類型,null 解析不了,空數組直接無響應,排版有各類問題,數據複雜了以後甚至基本的輸出文本都是錯的,諸如此類的問題不要太多。我也是人太好了,免費幫他當了一把測試人員。以這位老哥吊炸天的編碼能力都寫出了這麼多的 bug,我想我甚至都低估了我當初作這個項目時付出的精力。只是這種努力,恐怕在他看來仍是不值一提。
固然,道歉是不可能道歉的,目前來看一切彷佛都是個人錯。
感謝 @呂中宜,@FeelsChaotic 兩位提醒我用文本對比工具。
下面附上我提交的兩個核心文件的對比結果,額外說明一下,個人代碼使用的是1月份的,另一我的的代碼使用的是3月份 github 第一次提交的。
對比結果:
106 個相同行
11 個不重要的左邊獨有行
12 個不重要的右邊獨有行
4 個不重要的差別行
10 個重要的左邊獨有行
37 個重要的右邊獨有行
19 個重要差別行
25 個差別部分
對比結果:
108 個相同行
2 個重要右邊獨有行
2 個重要差別行
4 個差別部分
那位老哥在 github issue 上回復我了
對此我想說的是:
1.有問題能夠提 issue, 也能夠 fork,心情好的話改了以後還能夠提 PR,心情很差就本身用本身的修改版。我我的不能認同由於個人代碼不能被直接使用在你我的的項目中,就直接 copy 個人代碼,刪掉個人註釋,改幾個命名,而後做爲你的原創項目發佈到網上去。
2."因而我本地作了大量改動",說實話,或許這位哥們還以爲本身很委屈,以爲本身改了不少代碼,可是我以爲比起我從零作起,這點真的不值一提。不管是判斷一下空值,仍是類型有問題,放我手上都是分分鐘解決的問題,犯得上你如此辛苦作這麼大奉獻嗎?
3."此時的代碼基本只有json字符串與json對象轉換工具類是使用你的庫裏的",若是你以爲你只用了我這點代碼,或者你以爲我這點代碼不值一提,爲何不本身重寫,反而讓我一看處處都是個人代碼?
4."硬要說網上的代碼都是不容許別人使用的那我也沒辦法啊",看到這裏我真是啼笑皆非,這還都是個人錯咯?究竟是誰該委屈啊?我以前連 LICENSE 都沒加一個,難道我會不讓別人用?刪我註釋、本身發佈這個核心問題就被這麼給忽略掉了?
5."之後有時間我把裏面的那個工具類重構下就是了",鬧了半天,copy 了整個項目,隨便改了幾個地方,如今還以爲就用了下工具類?
小弟不才,去年學習 flutter 的過程當中,搞過幾個小玩具,其中就有一個將 json 數據轉換成 dart class 的 idea 插件。
不想點的朋友能夠看一下 gif
半年多來,隨着 flutter 的火熱,github 上也有了那麼幾十個 star。後來我也發佈到了全家桶插件官網。陸陸續續也有幾千個的下載量了。對於我這個小透明來講,仍是挺開心的,無論寫得有多爛,總歸是有人在用,總歸是爲 flutter 的生態貢獻了本身的一點綿薄之力。
然而就在今天,當我想去看看那些下載量更高的同類項目的時候,很不湊巧的就讓我發現了這麼一個做品:
先上一張他的 gif 吧
敏感的我,一會兒就感受到了有點不對勁,因而我點開了他的源碼開始查看,有以下收穫:
1.ClassGenerator 類名同樣的
2.NameValuePair/NamePair 極其類似,並且講道理,NamePair 這個命名很不天然
3.Param 類名同樣
4.Util/Utils 基本沒差異
沒耐心的朋友能夠不用看代碼,我以個人人格擔保,最後的結論是沒錯的
class ClassGenerator(private val generateComments: Boolean, private val ignoreEmptyOrNull: Boolean) {
val classes = mutableMapOf<String, List<Param>>()
fun generate(name: String, string: String): String {
return try {
val parseResult = JsonParser().parse(string)
val json: JsonObject? = if (parseResult.isJsonObject) {
parseResult.asJsonObject
} else if (parseResult.isJsonArray) {
parseResult.asJsonArray[0].asJsonObject
} else null
val fields = Param.json2Params(json)
"class $name {\n${printClassWithParams(fields, 2, name)}\n}\n${buildClasses()}"
} catch (jsonParseException: JsonParseException) {
jsonParseException.printStackTrace()
"error: not supported json"
} catch (illegalStateException: IllegalStateException) {
illegalStateException.printStackTrace()
if (illegalStateException.message?.startsWith("Not a JSON Object") == true) {
"error: not supported json"
} else {
"error: unknown"
}
}
}
private fun printClassWithParams(params: List<Param>, space: Int, className: String): String {
val commentSb = StringBuilder()
val sb = StringBuilder()
val tempClasses = HashMap<String, List<Param>>() // 統計子類
var spaceStr = ""
repeat(space) { spaceStr += " " }
val commentPrefix = "$spaceStr *"
fun List<Param>.insertComment(): List<Param> {
return if (generateComments) this.map {
commentSb.append(commentPrefix).append(" ${it.comment}\n")
it
} else this
}
/* 基本類型參數聲明與統計 **/
val orderedList = params
.filter { it.key == "String" || it.key == "int" || it.key == "double" || it.key == "bool" || (!ignoreEmptyOrNull && it.key == "dynamic") }
.sortedBy { it.key }
.insertComment()
.map {
sb.append("$spaceStr${it.key} ${it.value};\n")
it.value
}
/* 對象類型參數聲明與統計 **/
val objectList = params
.filter { it.key == "object" }
.sortedBy { it.value }
.insertComment()
.map {
val clazzName = Util.toUpperCaseFirstOne(it.value + "Bean")
classes[clazzName] = it.clazz
tempClasses[clazzName] = it.clazz
sb.append(spaceStr).append(clazzName).append(" ").append(it.value).append(";").append("\n")
NameValuePair(clazzName, it.value)
}
/* 基本類型 list 參數聲明與統計 **/
val listBaseList = params
.filter { it.key.startsWith("List<") }
.filterNot { it.key.contains("null") }
.sortedBy { it.value }
.insertComment()
.map {
sb.append(spaceStr).append(it.key).append(" ").append(it.value).append(";").append("\n")
NameValuePair(it.key, it.value)
}
/* 對象類型 list 參數聲明與統計 **/
val listList = params
.filter { "list" == it.key }
.filter { it.clazz != null }
.sortedBy { it.value }
.insertComment()
.map {
val clazzName = Util.toUpperCaseFirstOne(it.value + "ListBean")
classes[clazzName] = it.clazz
tempClasses[clazzName] = it.clazz
sb.append(spaceStr).append("List<").append(clazzName).append(">").append(" ").append(it.value).append(";").append("\n")
NameValuePair(clazzName, it.value)
}
/* dynamic list **/
var dynamiclist: List<NameValuePair>? = null
if (!ignoreEmptyOrNull) {
dynamiclist = params
.filter { it.key == "dynamicList" }
.sortedBy { it.value }
.insertComment()
.map {
sb.append(spaceStr).append("List<dynamic>").append(" ").append(it.value).append(";").append("\n")
NameValuePair(it.key, it.value)
}
}
val tempSpaceStr = "$spaceStr "
/* map.value 轉換爲對象的靜態函數 start **/
val fieldName = Util.toLowerCaseFirstOne(className)
sb.append("\n").append(spaceStr)
.append("static ").append(className).append(" fromMap").append("(Map<String, dynamic> map) {")
.append("\n").append(tempSpaceStr)
.append(className).append(" ").append(fieldName).append(" = new ").append(className).append("();")
orderedList.forEach {
sb.append("\n").append(tempSpaceStr).append(fieldName).append(".").append(it).append(" = ").append("map['").append(it).append("'];")
}
dynamiclist?.forEach {
sb.append("\n").append(tempSpaceStr).append(fieldName).append(".").append(it.value).append(" = ").append("map['").append(it.value).append("'];");
}
objectList.forEach {
sb.append("\n").append(tempSpaceStr).append(fieldName).append(".").append(it.value).append(" = ").append(it.name).append(".fromMap(map['").append(it.value).append("']);")
}
listList.forEach {
sb.append("\n").append(tempSpaceStr).append(fieldName).append(".").append(it.value).append(" = ").append(it.name).append(".fromMapList(map['").append(it.value).append("']);")
}
/* map.value 轉換爲基礎類型 list start **/
if (listBaseList.isNotEmpty())
sb.append("\n")
for ((count, pair) in listBaseList.withIndex()) {
sb.append("\n").append(tempSpaceStr).append("List<dynamic> dynamicList").append(count).append(" = map['").append(pair.value).append("'] ?? [];")
sb.append("\n").append(tempSpaceStr).append(fieldName).append(".").append(pair.value).append(" = new List();")
var function = "o.toString()"
when (pair.name) {
"List<int>" -> function = "int.parse(o.toString())"
"List<double>" -> function = "double.parse(o.toString())"
"List<bool>" -> function = "o.toString() == 'true'"
}
sb.append("\n").append(tempSpaceStr).append(fieldName).append(".").append(pair.value).append(".addAll(dynamicList").append(count).append(".map((o) => ").append(function).append("));")
sb.append("\n")
}
/* map.value 轉換爲基礎類型 list end **/
sb.append("\n").append(tempSpaceStr).append("return ").append(fieldName).append(";\n")
sb.append(spaceStr).append("}\n")
/* map.value 轉換爲對象的靜態函數 end **/
/* map.value 轉換爲 list 的靜態函數 start **/
sb.append("\n").append(spaceStr)
.append("static ").append("List<").append(className).append(">").append(" fromMapList").append("(dynamic mapList) {")
.append("\n").append(tempSpaceStr).append("if (mapList == null) return [];")
.append("\n").append(tempSpaceStr).append("List<").append(className).append("> list = new List(mapList.length);")
.append("\n").append(tempSpaceStr).append("for (int i = 0; i < mapList.length; i++) {")
.append("\n").append(tempSpaceStr).append(" ").append("list[i] = fromMap(mapList[i]);")
.append("\n").append(tempSpaceStr).append("}")
.append("\n").append(tempSpaceStr).append("return list;")
.append("\n").append(spaceStr).append("}")
.append("\n")
/* map.value 轉換爲 list 的靜態函數 end **/
// 遍歷類中類(主要目的是添加進 classes 統計,而不 append)
// 仍是因爲 dart 不支持內部類致使的
tempClasses.forEach { key, value ->
printClassWithParams(value, space + 2, key)
}
val commentString = if (commentSb.toString().isBlank() || commentSb.isEmpty()) {
""
} else {
"\n$spaceStr/**\n$commentSb$spaceStr */\n\n"
}
return "$commentString$sb"
}
private fun buildClasses(): String {
val sb = StringBuilder()
// 開始定義類
classes.forEach { key, value ->
sb.append("\n")
.append("class").append(" ").append(key).append(" ").append("{").append("\n")
.append(printClassWithParams(value, 2, key))
.append("}").append("\n")
}
return sb.toString()
}
}
複製代碼
class ClassGenerator {
val classes = mutableMapOf<String, List<Param>>()
fun generate(name: String, jsonText: String): String {
return try {
val fields = Param.json2Params(JsonParser().parse(jsonText).asJsonObject)
"class $name {\n${printClassWithParams(fields, 2, name)}\n}\n${buildClasses()}"
} catch (jsonParseException: JsonParseException) {
jsonParseException.printStackTrace()
"error: not supported json"
} catch (illegalStateException: IllegalStateException) {
illegalStateException.printStackTrace()
if (illegalStateException.message?.startsWith("Not a JSON Object") == true) {
"error: not supported json"
} else {
"error: unknown"
}
}
}
fun generate(name: String, fields: JsonObject): String {
return try {
"class $name {\n${printClassWithParams(Param.json2Params(fields), 2, name)}\n}\n${buildClasses()}"
} catch (jsonParseException: JsonParseException) {
jsonParseException.printStackTrace()
"error: not supported json"
} catch (illegalStateException: IllegalStateException) {
illegalStateException.printStackTrace()
if (illegalStateException.message?.startsWith("Not a JSON Object") == true) {
"error: not supported json"
} else {
"error: unknown"
}
}
}
private fun printClassWithParams(params: List<Param>, space: Int, className: String): String {
val sb = StringBuilder()
val tempClasses = HashMap<String, List<Param>>()
var spaceStr = ""
repeat(space) { spaceStr += " " }
val orderedList = params
.filter { it.key == "String" || it.key == "int" || it.key == "double" || it.key == "bool" || it.key == "num" }
.sortedBy { it.key }
.map {
sb.append("$spaceStr${it.key} ${it.camelWord};\n")
NameValuePair(it.value, it.camelWord)
}
val objectList = params
.filter { it.key == "object" }
.sortedBy { it.value }
.map {
val clazzName = Utils.toUpperCaseFirstOne(it.value + "Bean")
classes[clazzName] = it.clazz
tempClasses[clazzName] = it.clazz
sb.append(spaceStr).append(clazzName).append(" ").append(it.camelWord).append(";").append("\n")
NamePair(it.camelWord, clazzName, it.value)
}
val listBaseList = params
.filter { it.key.startsWith("List<") }
.sortedBy { it.value }
.map {
sb.append(spaceStr).append(it.key).append(" ").append(it.camelWord).append(";").append("\n")
NamePair(it.camelWord, it.key, it.value)
}
val listList = params
.filter { "list" == it.key }
.sortedBy { it.value }
.map {
val clazzName = Utils.toUpperCaseFirstOne(it.value + "ListBean")
classes[clazzName] = it.clazz
tempClasses[clazzName] = it.clazz
sb.append(spaceStr).append("List<").append(clazzName).append(">").append(" ").append(it.camelWord).append(";").append("\n")
NamePair(it.camelWord, clazzName, it.value)
}
val tempSpaceStr = "$spaceStr "
/**
* 構造
*/
sb.append("\n").append(spaceStr)
.append(className).append("({")
orderedList.forEach {
sb.append("this").append(".").append(it.value)
sb.append(", ")
}
objectList.forEach {
sb.append("this").append(".").append(it.camelKey)
sb.append(", ")
}
listList.forEach {
sb.append("this").append(".").append(it.camelKey)
sb.append(", ")
}
listBaseList.forEach {
sb.append("this").append(".").append(it.camelKey)
sb.append(", ")
}
if (sb.endsWith(", ")) {
sb.delete(sb.lastIndexOf(", "), sb.length)
}
sb.append("});\n")
sb.append("\n").append(spaceStr)
.append(className).append(".fromJson").append("(Map<String, dynamic> json) {")
.append(tempSpaceStr)
orderedList.forEach {
sb.append("\n").append(tempSpaceStr).append("this").append(".").append(it.value).append(" = ").append("json['").append(it.name).append("'];")
}
objectList.forEach {
sb.append("\n").append(tempSpaceStr).append("this").append(".").append(it.camelKey).append(" = ").append("json['").append(it.value).append("'] != null? ").append(it.key).append(".fromJson(json['").append(it.value).append("']) : null;")
}
listList.forEach {
sb.append("\n").append(tempSpaceStr).append("this").append(".").append(it.camelKey).append(" = ").append("(json['").append(it.value).append("'] as List)!=null?(json['").append(it.value).append("'] as List).map((i) => ").append(it.key).append(".fromJson(i)).toList():null;")
}
listBaseList.forEach {
sb.append("\n")
sb.append("\n").append(tempSpaceStr).append("List<dynamic> ").append(it.camelKey).append("List").append(" = json['").append(it.value).append("'];")
sb.append("\n").append(tempSpaceStr).append("this").append(".").append(it.camelKey).append(" = new List();")
var function = "o.toString()"
when (it.key) {
"List<int>" -> function = "int.parse(o.toString())"
"List<double>" -> function = "double.parse(o.toString())"
"List<bool>" -> function = "o.toString() == 'true'"
}
sb.append("\n").append(tempSpaceStr).append("this").append(".").append(it.camelKey).append(".addAll(").append(it.camelKey).append("List").append(".map((o) => ").append(function).append("));")
}
sb.append("\n").append(spaceStr).append("}\n\n")
sb.append(spaceStr)
.append("Map<String, dynamic> toJson() {\n").append(tempSpaceStr).append("final Map<String, dynamic> data = new Map<String, dynamic>();")
orderedList.forEach {
sb.append("\n").append(tempSpaceStr).append("data['").append(it.name).append("'] = ").append("this").append(".").append(it.value).append(";")
}
objectList.forEach {
sb.append("\n").append(tempSpaceStr).append("data['").append(it.value).append("'] = ").append("this").append(".").append(it.camelKey).append(".toJson();")
}
listList.forEach {
sb.append("\n").append(tempSpaceStr).append("data['").append(it.value).append("'] = ").append("this").append(".").append(it.camelKey).append(" != null?this.").append(it.camelKey).append(".map((i) => i.toJson()).toList():null;")
}
listBaseList.forEach {
sb.append("\n").append(tempSpaceStr).append("data['").append(it.value).append("'] = ").append("this").append(".").append(it.camelKey).append(";")
}
sb.append("\n").append(tempSpaceStr).append("return data;\n")
sb.append(spaceStr).append("}\n")
tempClasses.forEach { key, value ->
printClassWithParams(value, space + 2, key)
}
return sb.toString()
}
private fun buildClasses(): String {
val sb = StringBuilder()
classes.forEach { key, value ->
sb.append("\n")
.append("class").append(" ").append(key).append(" ").append("{").append("\n")
.append(printClassWithParams(value, 2, key))
.append("}").append("\n")
}
return sb.toString()
}
}
複製代碼
是否是一個模子刻出來的?大量的函數名、屬性名都是一致的,換行空行也都是一致的
因爲我已經將 NameValuePair 用 kotlin 改寫了,下面的代碼是從 git 提交記錄裏找到的
/**
* Created by zhangll on 2018/8/3.
*/
public class NameValuePair {
String name;
String value;
public NameValuePair(String name, String value) {
this.name = name;
this.value = value;
}
}
複製代碼
public class NamePair {
private String camelKey;
private String key;
private String value;
public NamePair(String camelKey, String key, String value) {
this.camelKey = camelKey;
this.key = key;
this.value = value;
}
public String getCamelKey() {
return camelKey;
}
public void setCamelKey(String camelKey) {
this.camelKey = camelKey;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
複製代碼
乍一看彷佛不同,其實他只是多寫了 getter setter,又加了一個駝峯命名功能的字段。我怎麼看出來一致的呢?由於 NameValuePair 嚴格來講,就應該給屬性命名 name 和 value。而另外一我的的類名叫 NamePair,中間恰恰少了個 Value ,屬性命名卻又是 key(不是理論上的 name)、value,這是爲何呢?明眼人應該一看就知道了。
/**
* Created by zhangll on 2018/8/3.
*/
public class Param {
String key;
String value;
List<Param> clazz;
String comment;
/**
*
* @param key 變量名
* @param object 變量內容
* @return
*/
public static Param makeParam(String key, Object object) {
if (object == null || "null".equals(object.toString())) {
return new Param("dynamic", key, null, object);
}
if (object instanceof JsonObject) {
JsonObject jsonObject = (JsonObject) object;
return new Param("object", key, json2Params(jsonObject), jsonObject);
} else if (object instanceof JsonArray) {
JsonArray jsonArray = (JsonArray) object;
if (jsonArray.size() != 0) {
Object obj = jsonArray.get(0);
if (obj instanceof JsonObject) {
return new Param("list", key, json2Params(jsonArray.get(0).getAsJsonObject()), jsonArray);
} else if (obj instanceof JsonArray) {
return new Param("dynamicList", key, null, object);
} else {
Param temp = makeParam("placeholder", obj);
if (temp.key.equals("dynamic")) {
return new Param("dynamicList", key, null, object);
}
return new Param("List<" + temp.key + ">", key, null, object);
}
} else {
return new Param("dynamicList", key, null, object);
}
} else if (tryParseBoolean(object)) {
return new Param("bool", key, null, "true".equals(object.toString()));
} else if (tryParseInt(object)) {
return new Param("int", key, null, Integer.parseInt(object.toString()));
} else if (tryParseLong(object)) {
return new Param("int", key, null, Long.parseLong(object.toString()));
} else if (tryParseDouble(object)) {
return new Param("double", key, null, Double.parseDouble(object.toString()));
} else if (tryParseFloat(object)) {
return new Param("double", key, null, Float.parseFloat(object.toString()));
} else {
return new Param("String", key, null, object.toString());
}
}
public static List<Param> json2Params(JsonObject jsonObject) {
List<Param> list = new ArrayList<>();
for (Object o : jsonObject.entrySet()) {
Map.Entry entry = (Map.Entry) o;
list.add(Param.makeParam(entry.getKey().toString(), entry.getValue()));
}
return list;
}
private static boolean tryParseInt(Object object) {
try {
int i = Integer.parseInt(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseLong(Object object) {
try {
long i = Long.parseLong(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseDouble(Object object) {
try {
double d = Double.parseDouble(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseFloat(Object object) {
try {
float f = Float.parseFloat(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseBoolean(Object object) {
String b = object.toString();
return Objects.equals(b, "true") || Objects.equals(b, "false");
}
public Param(String key, String value, List<Param> clazz, Object content) {
this.key = key;
this.value = value;
this.clazz = clazz;
if (content == null) return;
// 註釋處理
this.comment = value + " : " + content.toString().replaceAll("\n", "");
}
@Override
public String toString() {
return "Param{" +
"key='" + key + '\'' + ", value='" + value + '\'' + ", classes=" + clazz + '}'; } } 複製代碼
public class Param {
String key;
String value;
String camelWord;
List<Param> clazz;
/**
*
* @param key 變量名
* @param object 變量內容
* @return
*/
public static Param makeParam(String key, Object object) {
if (object instanceof JsonObject) {
JsonObject jsonObject = (JsonObject) object;
return new Param("object", key, json2Params(jsonObject));
} else if (object instanceof JsonArray) {
JsonArray jsonArray = (JsonArray) object;
if (jsonArray.size() != 0) {
Object obj = jsonArray.get(0);
if (obj instanceof JsonObject) {
return new Param("list", key, json2Params(jsonArray.get(0).getAsJsonObject()));
} else {
Param temp = makeParam("placeholder", obj);
return new Param("List<" + temp.key + ">", key, null);
}
} else {
return new Param("list", key, null);
}
} else if (tryParseBoolean(object)) {
return new Param("bool", key, null);
} else if (tryParseInt(object)) {
return new Param("int", key, null);
} else if (tryParseLong(object)) {
return new Param("num", key, null);
} else if (tryParseDouble(object)) {
return new Param("double", key, null);
} else if (tryParseFloat(object)) {
return new Param("double", key, null);
} else {
return new Param("String", key, null);
}
}
public static List<Param> json2Params(JsonObject jsonObject) {
List<Param> list = new ArrayList<>();
for (Object o : jsonObject.entrySet()) {
Map.Entry entry = (Map.Entry) o;
list.add(Param.makeParam(entry.getKey().toString(), entry.getValue()));
}
return list;
}
private static boolean tryParseInt(Object object) {
try {
int i = Integer.parseInt(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseLong(Object object) {
try {
long i = Long.parseLong(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseDouble(Object object) {
try {
double d = Double.parseDouble(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseFloat(Object object) {
try {
float f = Float.parseFloat(object.toString());
return true;
} catch (Exception e) {
return false;
}
}
private static boolean tryParseBoolean(Object object) {
String b = object.toString();
return Objects.equals(b, "true") || Objects.equals(b, "false");
}
public Param(String key, String value, List<Param> clazz) {
this.key = key;
this.value = value;
this.camelWord = Utils.toUpperCaseParams(value);
this.clazz = clazz;
}
@Override
public String toString() {
return "Param{" +
"key='" + key + '\'' + ", value='" + value + '\'' + ", classes=" + clazz + '}'; } } 複製代碼
又是一個模子刻出來的。除了我新增了註釋功能和部分 bug 修復致使的代碼變更,他新增了駝峯命名功能。
/**
* Created by zhangll on 2018/8/3.
*/
public class Util {
/**
* 將字符串複製到剪切板。
*/
public static void setSysClipboardText(String writeMe) {
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(writeMe);
clip.setContents(tText, null);
}
// 首字母轉大寫
public static String toUpperCaseFirstOne(String s){
if(Character.isUpperCase(s.charAt(0)))
return s;
else
return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
}
// 首字母轉小寫
public static String toLowerCaseFirstOne(String s){
if(Character.isLowerCase(s.charAt(0)))
return s;
else
return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
}
// 將 string 寫入文件
public static void writeToFile(Project project, VirtualFile file, String content) {
Runnable runnable = () -> {
try {
file.setBinaryContent(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
};
WriteCommandAction.runWriteCommandAction(project, runnable);
}
}
複製代碼
public class Utils {
/**
* 將字符串複製到剪切板。
*/
public static void setSysClipboardText(String writeMe) {
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(writeMe);
clip.setContents(tText, null);
}
// 首字母轉大寫
public static String toUpperCaseFirstOne(String s) {
if (s.contains("_")) {
String[] a = s.split("_");
StringBuilder builder = new StringBuilder();
for (String anA : a) {
if (Character.isUpperCase(anA.charAt(0)))
builder.append(anA);
else
builder.append(Character.toUpperCase(anA.charAt(0))).append(anA.substring(1));
}
return builder.toString();
}
if (Character.isUpperCase(s.charAt(0)))
return s;
else
return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
}
// 下劃線參數轉駝峯
public static String toUpperCaseParams(String s) {
if (s.contains("_")) {
String[] a = s.split("_");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < a.length; i++) {
if (i==0){
builder.append(a[i]);
}
if (Character.isUpperCase(a[i].charAt(0)))
builder.append(a[i]);
else if (i != 0)
builder.append(Character.toUpperCase(a[i].charAt(0))).append(a[i].substring(1));
}
return builder.toString();
}
return s;
}
// 首字母轉小寫
public static String toLowerCaseFirstOne(String s) {
if (Character.isLowerCase(s.charAt(0)))
return s;
else
return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
}
// 將 string 寫入文件
public static void writeToFile(VirtualFile file, String content) {
try {
file.setBinaryContent(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
複製代碼
寫文件的代碼好像有不一樣?不要緊,我 git 里拉老代碼出來
// 將 string 寫入文件
public static void writeToFile(VirtualFile file, String content) {
try {
file.setBinaryContent(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
複製代碼
因此,惟一的不一樣就是我類頭有註釋,而他多了一個駝峯命名的方法。
若是就 copy 一下個人代碼過去用,其實我確定也沒什麼,按道理來講做爲一個程序猿我還應該以爲開心纔是。
可是 copy 了我整個項目,又極其不專業的只改了幾個不痛不癢的地方,改得欲蓋彌彰,留着項目結構、類命名、方法命名、空行、換行這些我的風格濃重的東西不動,我是 Kotlin 寫的地方他就是 Kotlin,我用 Java 寫的地方他就是 Java, 難道是由於核心邏輯看不懂不敢改動嗎?既然能本身加上駝峯命名的功能,想來也不至於。
若是隻是 copy 項目也就罷了,他甚至還發布到了全家桶插件的官網,若是不是由於下載量比我本身的插件還高,恐怕這事我到死都不會知道。
固然,他沒什麼錯,是我本身沒給開源項目加上 LICENSE。但想來就算我有 LICENSE,按他能去發佈插件這個勇氣來看,只怕也是不在意的。
有朋友跟我說,我應該開心,應該有成就感,由於至少這證實我作的東西是有價值的,但我以爲事情不該該這麼去看待。我花了心思去寫出來的東西,我心肝情願的開源,我心肝情願的給別人用,可是拿了個人心血去換個包裝貼上他本身的牌子,這誰能接受?
做爲一個喜歡 flutter 的開發者,我也不至於由於這事就喪了氣,儘管也付出了很多時間,作了很多迭代,但畢竟只是一個小玩具項目而已。只是此次被好好的上了一課,之後不論多小的項目,LICENSE 是必定不能少的。