APIJSON blog 4 AbstractSQLConfig Article 4

Keywords: Database JSON SQL

2021SC@SDUSC

Continue the analysis of AbstractSQLConfig last week. The following code is @ override

@Override
	public boolean isExplain() {
		return explain;
	}
	@Override
	public AbstractSQLConfig setExplain(boolean explain) {
		this.explain = explain;
		return this;
	}

	@Override
	public List<Join> getJoinList() {
		return joinList;
	}

Knowledge learning

@Override is pseudo code, which means rewriting. (of course, it's OK not to write @ override), but it has the following advantages:  
1. Can be used as notes for easy reading;
2. The compiler can verify whether the method name under @ Override is all in your parent class. If not, an error will be reported. For example, if you don't write @ Override and you write the following method name wrong, your compiler can compile it because the compiler thinks this method is an added method in your subclass.
 
For example, when overriding onCreate of the parent class, adding @ Override to the method can help you check the correctness of the method.
@Override
public void onCreate(Bundle savedInstanceState)

{.......}
This is correct if you write:

@Override
public void oncreate(Bundle savedInstanceState)
{.......}
The compiler will report the following error: The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method to ensure that you rewrite the oncreate method correctly (because oncreate should be oncreate).

If you do not add @ Override, the compiler will not detect errors, but will think that you have defined a new method for subclass: oncreate

  @ JSONField is used here

@JSONField(serialize = false)
	public int getOffset() {
		return getOffset(getPage(), getCount());
	}
	/**Get initial position offset
	 * @param page
	 * @param count
	 * @return
	 */
	public static int getOffset(int page, int count) {
		return page*count;
	}
	/**Get limit quantity
	 * @return
	 */
	@JSONField(serialize = false)
	public String getLimitString() {
		if (count <= 0 || RequestMethod.isHeadMethod(getMethod(), true)) {
			return "";
		}
		return getLimitString(getPage(), getCount(), isOracle() || isSQLServer() || isDb2(), isOracle());
	}
    public static String getLimitString(int page, int count, boolean isTSQL, boolean isOracle) {
		int offset = getOffset(page, count);

		if (isTSQL) {  // All keywords in OFFSET FECTH cannot be omitted. In addition, Oracle database uses sub query and where paging
			return isOracle ? " WHERE ROWNUM BETWEEN "+ offset +" AND "+ (offset + count) : " OFFSET " + offset + " ROWS FETCH FIRST " + count + " ROWS ONLY";
		}

		return " LIMIT " + count + (offset <= 0 ? "" : " OFFSET " + offset);  // OFFSET is not supported for delete and update
	}

Knowledge learning

Use @ JSONField annotation in fastjason
json format transfers data between servers. However, json format data does not conform to the variable definition rules in JAVA and is difficult to understand. Therefore, secondary processing needs to be done in the background to process the data into the format defined in our system.

Idea:

    1. Define the bean to be returned, and define the data to be returned in the bean

    2. Get the JSON string to be processed

    3. Convert JSON string into bean, and then return the converted bean to the client.

Because the key in json cannot match the attribute in bean, some attributes are null during conversion. After checking the official documents, it is found that @ JSONField can be used for explanation, but there is no detailed instructions.

@Action object of JSONField:

1. Field
2. Setter and Getter methods

Note: fastjason operates according to getter and setter methods, not according to Field.

Show me the code:

1, Action Field

@When JSONField acts on a Field, its name defines not only the name of the input key, but also the name of the output. When @ JSONField acts on the file Field, it defines the input and output. If the json format we transmit does not conform to this format, it cannot be converted correctly.

2, Acts on setter and getter methods

As the name suggests, when acting on a setter method, it is equivalent to looking for the corresponding value in json according to the name and calling the setter object for assignment.

When acting on a getter, when the bean is converted to json, its key value is the value defined by name.

The following is the analysis of getwhereString

Set<Entry<String, List<String>>> combineSet = combine == null ? null : combine.entrySet();

The combineSet is defined here using the set method

Knowledge learning

Set means a collection of the same kind of objects, < String > indicates that all such objects are String type objects.

You can do this:

Set<String> set = new HashSet<String>();
String s1 = "hello";

String s2 = "world";

set.add(s1);

set.add(s2);
Two elements are added.

		for (Entry<String, List<String>> ce : combineSet) {
			keyList = ce == null ? null : ce.getValue();
			if (keyList == null || keyList.isEmpty()) {
				continue;
			}

			if ("|".equals(ce.getKey())) {
				logic = Logic.TYPE_OR;
			}
			else if ("!".equals(ce.getKey())) {
				logic = Logic.TYPE_NOT;
			}
			else {
				logic = Logic.TYPE_AND;
			}


			isItemFirst = true;
			cs = "";
			for (String key : keyList) {
				c = getWhereItem(key, where.get(key), method, verifyName);

				if (StringUtil.isEmpty(c, true)) {//Avoid SQL conditional connection errors
					continue;
				}

				cs += (isItemFirst ? "" : (Logic.isAnd(logic) ? AND : OR)) + "(" + c + ")";

				isItemFirst = false;
			}

			if (StringUtil.isEmpty(cs, true)) {//Avoid SQL conditional connection errors
				continue;
			}

			whereString += (isCombineFirst ? "" : AND) + (Logic.isNot(logic) ? NOT : "") + " (  " + cs + "  ) ";
			isCombineFirst = false;
		}

  Here is the judgment of the SQL connection and condition of the WHERE statement in the SQL language, followed by the judgment of the error type of the join, which can be divided into the following categories

throw new NotExistException("no result for ! OUTER JOIN( ! (A | B) ) when A or B is empty!")

throw new NotExistException("no result for ) FOREIGN JOIN( B & ! A ) when A is empty!");

throw new NotExistException("no result for ! OUTER JOIN( ! (A | B) ) when A or B is empty!");

throw new NotExistException("no result for ( ANTI JOIN( A & ! B ) when B is empty!");

throw new NotExistException("no result for ^ SIDE JOIN( ! (A & B) ) when both A and B are empty!");

Throw new unsupported operationexception ("write operation request must be conditional!!!");

protected String getWhereItem(String key, Object value, RequestMethod method, boolean verifyName) throws Exception {
		Log.d(TAG, "getWhereItem  key = " + key);
		//Avoid filtering to all 	 value = key == null ? null : where.get(key);
		if (key == null || value == null || key.endsWith("()") || key.startsWith("@")) { //Keyword | method, + or - direct error reporting
			Log.d(TAG, "getWhereItem  key == null || value == null"
					+ " || key.startsWith(@) || key.endsWith(()) >> continue;");
			return null;
		}
		if (key.endsWith("@")) {//quote
			//	key = key.substring(0, key.lastIndexOf("@"));
			throw new IllegalArgumentException(TAG + ".getWhereItem: character " + key + " wrongful!");
		}

		// Original SQL fragment
		String rawSQL = getRawSQL(key, value);

		int keyType;
		if (key.endsWith("$")) {
			keyType = 1;
		} 
		else if (key.endsWith("~")) {
			keyType = key.charAt(key.length() - 2) == '*' ? -2 : 2;  //FIXME StringIndexOutOfBoundsException
		}
		else if (key.endsWith("%")) {
			keyType = 3;
		}
		else if (key.endsWith("{}")) {
			keyType = 4;
		}
		else if (key.endsWith("}{")) {
			keyType = 5;
		}
		else if (key.endsWith("<>")) {
			keyType = 6;
		}
		else if (key.endsWith(">=")) {
			keyType = 7;
		}
		else if (key.endsWith("<=")) {
			keyType = 8;
		}
		else if (key.endsWith(">")) {
			keyType = 9;
		}
		else if (key.endsWith("<")) {
			keyType = 10;
		} else {  // else absolutely can't save, avoid stepping on the pit again! keyType = 0;  I didn't notice it written outside the for loop!
			keyType = 0;
		}

		key = getRealKey(method, key, false, true, verifyName);

		switch (keyType) {
		case 1:
			return getSearchString(key, value, rawSQL);
		case -2:
		case 2:
			return getRegExpString(key, value, keyType < 0, rawSQL);
		case 3:
			return getBetweenString(key, value, rawSQL);
		case 4:
			return getRangeString(key, value, rawSQL);
		case 5:
			return getExistsString(key, value, rawSQL);
		case 6:
			return getContainString(key, value, rawSQL);
		case 7:
			return getCompareString(key, value, ">=", rawSQL);
		case 8:
			return getCompareString(key, value, "<=", rawSQL);
		case 9:
			return getCompareString(key, value, ">", rawSQL);
		case 10:
			return getCompareString(key, value, "<", rawSQL);
		default:  // Field comparison key = '[]' of TODO MySQL JSON type will have no result! Key like '[1, 2, 3]' / / todo mysql, followed by a space!
			return getEqualString(key, value, rawSQL);
		}
	}

Different symbols are treated differently here  

The method getRegExpString defined later is used,   getBetweenString,getRangeString,getExistsString,   getContainString, getEqualString these methods will be analyzed in the next blog

Here is getRegExpString

	@JSONField(serialize = false)
	public String getRegExpString(String key, Object value, boolean ignoreCase, String rawSQL) throws IllegalArgumentException {
		if (rawSQL != null) {
			throw new UnsupportedOperationException("@raw:value in " + key + " wrongful!@raw I won't support it key~ This function symbol! Only support key, key!, key<, key{} Equal comparison operation sum @column, @having !");
		}
		if (value == null) {
			return "";
		}

		Logic logic = new Logic(key);
		key = logic.getKey();
		Log.i(TAG, "getRegExpString key = " + key);

		JSONArray arr = newJSONArray(value);
		if (arr.isEmpty()) {
			return "";
		}
		return getRegExpString(key, arr.toArray(), logic.getType(), ignoreCase);
	}
	/**search key match RegExp values
	 * @param key
	 * @param values
	 * @param type 
	 * @param ignoreCase 
	 * @return LOGIC [  key REGEXP 'values[i]' ]
	 * @throws IllegalArgumentException 
	 */
	@JSONField(serialize = false)
	public String getRegExpString(String key, Object[] values, int type, boolean ignoreCase) throws IllegalArgumentException {
		if (values == null || values.length <= 0) {
			return "";
		}

		String condition = "";
		for (int i = 0; i < values.length; i++) {
			if (values[i] instanceof String == false) {
				throw new IllegalArgumentException(key + "$:value in value The type of can only be String or String[]!");
			}
			condition += (i <= 0 ? "" : (Logic.isAnd(type) ? AND : OR)) + getRegExpString(key, (String) values[i], ignoreCase);
		}

		return getCondition(Logic.isNot(type), condition);
	}

	/**WHERE key REGEXP 'value'
	 * @param key
	 * @param value
	 * @param ignoreCase
	 * @return key REGEXP 'value'
	 */
	@JSONField(serialize = false)
	public String getRegExpString(String key, String value, boolean ignoreCase) {
		if (isPostgreSQL()) {
			return getKey(key) + " ~" + (ignoreCase ? "* " : " ") + getValue(value);
		}
		if (isOracle()) {
			return "regexp_like(" + getKey(key) + ", " + getValue(value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
		}
		if (isClickHouse()) {
			return "match(" + (ignoreCase ? "lower(" : "") + getKey(key) + (ignoreCase ? ")" : "") + ", " + (ignoreCase ? "lower(" : "") + getValue(value) + (ignoreCase ? ")" : "") + ")";
		}
		return getKey(key) + " REGEXP " + (ignoreCase ? "" : "BINARY ") + getValue(value);
	}

The method in Log is also used here

public static boolean DEBUG = true;

    public static void d(String TAG, String msg) {
        if (DEBUG) {
            logInfo(TAG,msg,"DEBUG");
        }
    }

The loginfo method is used here as follows

    public static void logInfo(String TAG, String msg, String level){
        if(level.equals("DEBUG") || level .equals("ERROR") ||level.equals("WARN")){
            System.err.println(dateFormat.format(System.currentTimeMillis()) + ": " + TAG + "." + level + ": " + msg);
        }
        else if(level.equals("VERBOSE") || level .equals("INFO") ){
            System.out.println(dateFormat.format(System.currentTimeMillis()) + ": " + TAG + "." + level + ": " + msg);
        }
    }

This is the log information table record of the calling method, when there is an error and when there is no error

Knowledge learning

What is the difference between System.err and System.out?
① java API, the explanation given in the document is: out is "standard output stream", err is "standard error output stream";  

② The runtime difference in eclipse is that the colors displayed are different, and the err output is displayed in red;      

③ Err.println outputs a random string position. However, the relative position between the strings output by err.println will not change. System.out has a caching function in both the JVM and the operating system, that is, what you output may not be output in real time. Sometimes it will be output only after a certain amount is accumulated. System.err will output in real time. If you use it alone, you may not feel it. If you use the two methods together, you will find it.

Record location 1957  

Posted by vickyjackson on Sat, 23 Oct 2021 20:04:48 -0700