Compare commits
1 Commits
main
...
authentica
Author | SHA1 | Date | |
---|---|---|---|
|
157b10925d |
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
package me.ratsiel.auth.abstracts;
|
||||
|
||||
/**
|
||||
* The class Authentication token.
|
||||
*/
|
||||
public abstract class AuthenticationToken {
|
||||
}
|
23
src/main/java/me/ratsiel/auth/abstracts/Authenticator.java
Normal file
23
src/main/java/me/ratsiel/auth/abstracts/Authenticator.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package me.ratsiel.auth.abstracts;
|
||||
|
||||
import me.ratsiel.json.Json;
|
||||
|
||||
/**
|
||||
* The class Authenticator is used to log in to mojang or microsoft
|
||||
*/
|
||||
public abstract class Authenticator<T> {
|
||||
|
||||
protected final Json json = new Json();
|
||||
|
||||
/**
|
||||
* Login string.
|
||||
*
|
||||
* @param email the email
|
||||
* @param password the password
|
||||
* @return the string
|
||||
*/
|
||||
public abstract T login(String email, String password);
|
||||
|
||||
|
||||
|
||||
}
|
79
src/main/java/me/ratsiel/auth/abstracts/TextureVariable.java
Normal file
79
src/main/java/me/ratsiel/auth/abstracts/TextureVariable.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package me.ratsiel.auth.abstracts;
|
||||
|
||||
/**
|
||||
* The type Texture variable stores data from {@link me.ratsiel.auth.model.mojang.profile.MinecraftProfile}
|
||||
*/
|
||||
public abstract class TextureVariable {
|
||||
|
||||
private String id;
|
||||
private String state;
|
||||
private String url;
|
||||
private String alias;
|
||||
|
||||
/**
|
||||
* Instantiates a new Texture variable.
|
||||
*/
|
||||
public TextureVariable() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Texture variable.
|
||||
*
|
||||
* @param id the id
|
||||
* @param state the state
|
||||
* @param url the url
|
||||
* @param alias the alias
|
||||
*/
|
||||
public TextureVariable(String id, String state, String url, String alias) {
|
||||
this.id = id;
|
||||
this.state = state;
|
||||
this.url = url;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets id.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets state.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets url.
|
||||
*
|
||||
* @return the url
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets alias.
|
||||
*
|
||||
* @return the alias
|
||||
*/
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TextureVariable{" +
|
||||
"id='" + id + '\'' +
|
||||
", state='" + state + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", alias='" + alias + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package me.ratsiel.auth.abstracts.exception;
|
||||
|
||||
/**
|
||||
* The class Authentication exception is thrown when something went wrong during authentication
|
||||
*/
|
||||
public class AuthenticationException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Instantiates a new Authentication exception.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
public AuthenticationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
package me.ratsiel.auth.model.microsoft;
|
||||
|
||||
import me.ratsiel.auth.abstracts.Authenticator;
|
||||
import me.ratsiel.auth.abstracts.exception.AuthenticationException;
|
||||
import me.ratsiel.json.model.JsonArray;
|
||||
import me.ratsiel.json.model.JsonObject;
|
||||
import me.ratsiel.json.model.JsonString;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The class Microsoft authenticator is used to log in into microsoft account and generate mojang JWT token
|
||||
*/
|
||||
public class MicrosoftAuthenticator extends Authenticator<XboxToken> {
|
||||
|
||||
protected final String clientId = "00000000402b5328";
|
||||
protected final String scopeUrl = "service::user.auth.xboxlive.com::MBI_SSL";
|
||||
|
||||
protected String loginUrl;
|
||||
protected String loginCookie;
|
||||
protected String loginPPFT;
|
||||
|
||||
@Override
|
||||
public XboxToken login(String email, String password) {
|
||||
MicrosoftToken microsoftToken = generateTokenPair(generateLoginCode(email, password));
|
||||
XboxLiveToken xboxLiveToken = generateXboxTokenPair(microsoftToken);
|
||||
return generateXboxTokenPair(xboxLiveToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate start login code from email and password
|
||||
*
|
||||
* @param email microsoft email
|
||||
* @param password microsoft password
|
||||
* @return login code
|
||||
*/
|
||||
private String generateLoginCode(String email, String password) {
|
||||
try {
|
||||
URL url = new URL("https://login.live.com/oauth20_authorize.srf?redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=" + scopeUrl + "&display=touch&response_type=code&locale=en&client_id=" + clientId);
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
|
||||
InputStream inputStream = httpURLConnection.getResponseCode() == 200 ? httpURLConnection.getInputStream() : httpURLConnection.getErrorStream();
|
||||
|
||||
loginCookie = httpURLConnection.getHeaderField("set-cookie");
|
||||
|
||||
String responseData = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining());
|
||||
Matcher bodyMatcher = Pattern.compile("sFTTag:[ ]?'.*value=\"(.*)\"/>'").matcher(responseData);
|
||||
if (bodyMatcher.find()) {
|
||||
loginPPFT = bodyMatcher.group(1);
|
||||
} else {
|
||||
throw new AuthenticationException("Authentication error. Could not find 'LOGIN-PFTT' tag from response!");
|
||||
}
|
||||
|
||||
bodyMatcher = Pattern.compile("urlPost:[ ]?'(.+?(?='))").matcher(responseData);
|
||||
if (bodyMatcher.find()) {
|
||||
loginUrl = bodyMatcher.group(1);
|
||||
} else {
|
||||
throw new AuthenticationException("Authentication error. Could not find 'LOGIN-URL' tag from response!");
|
||||
}
|
||||
|
||||
if (loginCookie == null || loginPPFT == null || loginUrl == null)
|
||||
throw new AuthenticationException("Authentication error. Error in authentication process!");
|
||||
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
|
||||
return sendCodeData(email, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send code data from email and password
|
||||
*
|
||||
* @param email microsoft email
|
||||
* @param password microsoft password
|
||||
* @return login code
|
||||
*/
|
||||
private String sendCodeData(String email, String password) {
|
||||
String authToken;
|
||||
|
||||
Map<String, String> requestData = new HashMap<>();
|
||||
|
||||
requestData.put("login", email);
|
||||
requestData.put("loginfmt", email);
|
||||
requestData.put("passwd", password);
|
||||
requestData.put("PPFT", loginPPFT);
|
||||
|
||||
String postData = encodeURL(requestData);
|
||||
|
||||
try {
|
||||
byte[] data = postData.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(loginUrl).openConnection();
|
||||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
|
||||
connection.setRequestProperty("Content-Length", String.valueOf(data.length));
|
||||
connection.setRequestProperty("Cookie", loginCookie);
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
try (OutputStream outputStream = connection.getOutputStream()) {
|
||||
outputStream.write(data);
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() != 200 || connection.getURL().toString().equals(loginUrl)) {
|
||||
throw new AuthenticationException("Authentication error. Username or password is not valid.");
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile("[?|&]code=([\\w.-]+)");
|
||||
|
||||
Matcher tokenMatcher = pattern.matcher(URLDecoder.decode(connection.getURL().toString(), StandardCharsets.UTF_8.name()));
|
||||
if (tokenMatcher.find()) {
|
||||
authToken = tokenMatcher.group(1);
|
||||
} else {
|
||||
throw new AuthenticationException("Authentication error. Could not handle data from response.");
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
|
||||
this.loginUrl = null;
|
||||
this.loginCookie = null;
|
||||
this.loginPPFT = null;
|
||||
|
||||
return authToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send xbox auth request
|
||||
*/
|
||||
private void sendXboxRequest(HttpURLConnection httpURLConnection, JsonObject request, JsonObject properties) throws IOException {
|
||||
request.add("Properties", properties);
|
||||
|
||||
String requestBody = request.toString();
|
||||
|
||||
httpURLConnection.setFixedLengthStreamingMode(requestBody.length());
|
||||
httpURLConnection.setRequestProperty("Content-Type", "application/json");
|
||||
httpURLConnection.setRequestProperty("Accept", "application/json");
|
||||
httpURLConnection.connect();
|
||||
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
|
||||
outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate {@link me.ratsiel.auth.model.mojang.MinecraftToken}
|
||||
*
|
||||
* @param authToken from {@link #generateLoginCode(String, String)}
|
||||
* @return {@link me.ratsiel.auth.model.mojang.MinecraftToken}
|
||||
*/
|
||||
private MicrosoftToken generateTokenPair(String authToken) {
|
||||
try {
|
||||
Map<String, String> arguments = new HashMap<>();
|
||||
arguments.put("client_id", clientId);
|
||||
arguments.put("code", authToken);
|
||||
arguments.put("grant_type", "authorization_code");
|
||||
arguments.put("redirect_uri", "https://login.live.com/oauth20_desktop.srf");
|
||||
arguments.put("scope", scopeUrl);
|
||||
|
||||
StringJoiner argumentBuilder = new StringJoiner("&");
|
||||
for (Map.Entry<String, String> entry : arguments.entrySet()) {
|
||||
argumentBuilder.add(encodeURL(entry.getKey()) + "=" + encodeURL(entry.getValue()));
|
||||
}
|
||||
|
||||
byte[] data = argumentBuilder.toString().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
URL url = new URL("https://login.live.com/oauth20_token.srf");
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
|
||||
httpURLConnection.setRequestMethod("POST");
|
||||
httpURLConnection.setDoOutput(true);
|
||||
httpURLConnection.setFixedLengthStreamingMode(data.length);
|
||||
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
httpURLConnection.connect();
|
||||
|
||||
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
|
||||
outputStream.write(data);
|
||||
}
|
||||
|
||||
JsonObject jsonObject = parseResponseData(httpURLConnection);
|
||||
|
||||
return new MicrosoftToken(jsonObject.get("access_token", JsonString.class).getValue(), jsonObject.get("refresh_token", JsonString.class).getValue());
|
||||
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate {@link XboxLiveToken} from {@link MicrosoftToken}
|
||||
*
|
||||
* @param microsoftToken the microsoft token
|
||||
* @return the xbox live token
|
||||
*/
|
||||
public XboxLiveToken generateXboxTokenPair(MicrosoftToken microsoftToken) {
|
||||
try {
|
||||
URL url = new URL("https://user.auth.xboxlive.com/user/authenticate");
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
|
||||
httpURLConnection.setDoOutput(true);
|
||||
|
||||
JsonObject request = new JsonObject();
|
||||
request.add("RelyingParty", new JsonString("http://auth.xboxlive.com"));
|
||||
request.add("TokenType", new JsonString("JWT"));
|
||||
|
||||
JsonObject properties = new JsonObject();
|
||||
properties.add("AuthMethod", new JsonString("RPS"));
|
||||
properties.add("SiteName", new JsonString("user.auth.xboxlive.com"));
|
||||
properties.add("RpsTicket", new JsonString(microsoftToken.getToken()));
|
||||
|
||||
sendXboxRequest(httpURLConnection, request, properties);
|
||||
|
||||
JsonObject jsonObject = parseResponseData(httpURLConnection);
|
||||
|
||||
String uhs = ((JsonObject) (jsonObject.get("DisplayClaims", JsonObject.class)).get("xui", JsonArray.class).get(0)).get("uhs", JsonString.class).getValue();
|
||||
return new XboxLiveToken(jsonObject.get("Token", JsonString.class).getValue(), uhs);
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate {@link XboxToken} from {@link XboxLiveToken}
|
||||
*
|
||||
* @param xboxLiveToken the xbox live token
|
||||
* @return the xbox token
|
||||
*/
|
||||
public XboxToken generateXboxTokenPair(XboxLiveToken xboxLiveToken) {
|
||||
try {
|
||||
URL url = new URL("https://xsts.auth.xboxlive.com/xsts/authorize");
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
|
||||
httpURLConnection.setRequestMethod("POST");
|
||||
httpURLConnection.setDoOutput(true);
|
||||
|
||||
JsonObject request = new JsonObject();
|
||||
request.add("RelyingParty", new JsonString("rp://api.minecraftservices.com/"));
|
||||
request.add("TokenType", new JsonString("JWT"));
|
||||
|
||||
JsonObject properties = new JsonObject();
|
||||
properties.add("SandboxId", new JsonString("RETAIL"));
|
||||
JsonArray userTokens = new JsonArray();
|
||||
userTokens.add(new JsonString(xboxLiveToken.getToken()));
|
||||
properties.add("UserTokens", userTokens);
|
||||
|
||||
sendXboxRequest(httpURLConnection, request, properties);
|
||||
|
||||
if (httpURLConnection.getResponseCode() == 401) {
|
||||
throw new AuthenticationException("No xbox account was found!");
|
||||
}
|
||||
|
||||
JsonObject jsonObject = parseResponseData(httpURLConnection);
|
||||
|
||||
String uhs = ((JsonObject) (jsonObject.get("DisplayClaims", JsonObject.class)).get("xui", JsonArray.class).get(0)).get("uhs", JsonString.class).getValue();
|
||||
return new XboxToken(jsonObject.get("Token", JsonString.class).getValue(), uhs);
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse response data to {@link JsonObject}
|
||||
*
|
||||
* @param httpURLConnection the http url connection
|
||||
* @return the json object
|
||||
* @throws IOException the io exception
|
||||
*/
|
||||
public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException {
|
||||
BufferedReader bufferedReader;
|
||||
|
||||
if (httpURLConnection.getResponseCode() != 200) {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream()));
|
||||
} else {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
|
||||
}
|
||||
String lines = bufferedReader.lines().collect(Collectors.joining());
|
||||
|
||||
JsonObject jsonObject = json.fromJsonString(lines, JsonObject.class);
|
||||
if (jsonObject.has("error")) {
|
||||
throw new AuthenticationException(jsonObject.get("error") + ": " + jsonObject.get("error_description"));
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode url string.
|
||||
*
|
||||
* @param url the url
|
||||
* @return the string
|
||||
*/
|
||||
private String encodeURL(String url) {
|
||||
try {
|
||||
return URLEncoder.encode(url, "UTF-8");
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
throw new UnsupportedOperationException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode url string.
|
||||
*
|
||||
* @param map the map
|
||||
* @return the string
|
||||
*/
|
||||
private String encodeURL(Map<String, String> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(String.format("%s=%s",
|
||||
encodeURL(entry.getKey().toString()),
|
||||
encodeURL(entry.getValue().toString())
|
||||
));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package me.ratsiel.auth.model.microsoft;
|
||||
|
||||
import me.ratsiel.auth.abstracts.AuthenticationToken;
|
||||
|
||||
/**
|
||||
* The class Microsoft token stores token and refreshToken
|
||||
*/
|
||||
public class MicrosoftToken extends AuthenticationToken {
|
||||
|
||||
protected String token;
|
||||
protected String refreshToken;
|
||||
|
||||
/**
|
||||
* Instantiates a new Microsoft token.
|
||||
*/
|
||||
public MicrosoftToken() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Microsoft token.
|
||||
*
|
||||
* @param token the token
|
||||
* @param refreshToken the refresh token
|
||||
*/
|
||||
public MicrosoftToken(String token, String refreshToken) {
|
||||
this.token = token;
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets token.
|
||||
*
|
||||
* @return the token
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets refresh token.
|
||||
*
|
||||
* @return the refresh token
|
||||
*/
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package me.ratsiel.auth.model.microsoft;
|
||||
|
||||
import me.ratsiel.auth.abstracts.AuthenticationToken;
|
||||
|
||||
/**
|
||||
* The class Xbox live token stores token and uhs
|
||||
*/
|
||||
public class XboxLiveToken extends AuthenticationToken {
|
||||
|
||||
protected String token;
|
||||
protected String uhs;
|
||||
|
||||
/**
|
||||
* Instantiates a new Xbox live token.
|
||||
*/
|
||||
public XboxLiveToken() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Xbox live token.
|
||||
*
|
||||
* @param token the token
|
||||
* @param uhs the uhs
|
||||
*/
|
||||
public XboxLiveToken(String token, String uhs) {
|
||||
this.token = token;
|
||||
this.uhs = uhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets token.
|
||||
*
|
||||
* @return the token
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets uhs.
|
||||
*
|
||||
* @return the uhs
|
||||
*/
|
||||
public String getUhs() {
|
||||
return uhs;
|
||||
}
|
||||
|
||||
|
||||
}
|
24
src/main/java/me/ratsiel/auth/model/microsoft/XboxToken.java
Normal file
24
src/main/java/me/ratsiel/auth/model/microsoft/XboxToken.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package me.ratsiel.auth.model.microsoft;
|
||||
|
||||
/**
|
||||
* The class xbox token has the same functions as {@link XboxLiveToken}
|
||||
*/
|
||||
public class XboxToken extends XboxLiveToken {
|
||||
|
||||
/**
|
||||
* Instantiates a new Xbox token.
|
||||
*/
|
||||
public XboxToken() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Xbox token.
|
||||
*
|
||||
* @param token the token
|
||||
* @param uhs the uhs
|
||||
*/
|
||||
public XboxToken(String token, String uhs) {
|
||||
super(token, uhs);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
package me.ratsiel.auth.model.mojang;
|
||||
|
||||
import me.ratsiel.auth.abstracts.Authenticator;
|
||||
import me.ratsiel.auth.abstracts.exception.AuthenticationException;
|
||||
import me.ratsiel.auth.model.microsoft.MicrosoftAuthenticator;
|
||||
import me.ratsiel.auth.model.microsoft.XboxToken;
|
||||
import me.ratsiel.auth.model.mojang.profile.MinecraftCape;
|
||||
import me.ratsiel.auth.model.mojang.profile.MinecraftProfile;
|
||||
import me.ratsiel.auth.model.mojang.profile.MinecraftSkin;
|
||||
import me.ratsiel.json.Json;
|
||||
import me.ratsiel.json.model.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The class Minecraft authenticator is used to log in with normal minecraft details or with microsoft
|
||||
*/
|
||||
public class MinecraftAuthenticator extends Authenticator<MinecraftToken> {
|
||||
|
||||
/**
|
||||
* The Microsoft authenticator is used for {@link #loginWithXbox(String, String)}
|
||||
*/
|
||||
protected final MicrosoftAuthenticator microsoftAuthenticator = new MicrosoftAuthenticator();
|
||||
|
||||
@Override
|
||||
public MinecraftToken login(String email, String password) {
|
||||
try {
|
||||
URL url = new URL("https://authserver.mojang.com/authenticate");
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
|
||||
httpURLConnection.setRequestMethod("POST");
|
||||
httpURLConnection.setDoOutput(true);
|
||||
|
||||
JsonObject request = new JsonObject();
|
||||
JsonObject agent = new JsonObject();
|
||||
agent.add(new JsonString("name", "Minecraft"));
|
||||
agent.add(new JsonNumber("version", "1"));
|
||||
request.add("agent", agent);
|
||||
request.add(new JsonString("username", email));
|
||||
request.add(new JsonString("password", password));
|
||||
request.add(new JsonBoolean("requestUser", false));
|
||||
|
||||
|
||||
String requestBody = request.toString();
|
||||
|
||||
httpURLConnection.setFixedLengthStreamingMode(requestBody.length());
|
||||
httpURLConnection.setRequestProperty("Content-Type", "application/json");
|
||||
httpURLConnection.setRequestProperty("Host", "authserver.mojang.com");
|
||||
httpURLConnection.connect();
|
||||
|
||||
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
|
||||
outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII));
|
||||
}
|
||||
|
||||
JsonObject jsonObject = parseResponseData(httpURLConnection);
|
||||
return new MinecraftToken(jsonObject.get("accessToken", JsonString.class).getValue(), ((JsonObject)jsonObject.get("selectedProfile")).get("name", JsonString.class).getValue());
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with microsoft email and microsoft password
|
||||
*
|
||||
* @param email the email
|
||||
* @param password the password
|
||||
* @return the minecraft token
|
||||
*/
|
||||
public MinecraftToken loginWithXbox(String email, String password) {
|
||||
XboxToken xboxToken = microsoftAuthenticator.login(email, password);
|
||||
|
||||
try {
|
||||
URL url = new URL("https://api.minecraftservices.com/authentication/login_with_xbox");
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
|
||||
httpURLConnection.setRequestMethod("POST");
|
||||
httpURLConnection.setDoOutput(true);
|
||||
|
||||
JsonObject request = new JsonObject();
|
||||
request.add("identityToken", new JsonString("XBL3.0 x=" + xboxToken.getUhs() + ";" + xboxToken.getToken()));
|
||||
|
||||
String requestBody = request.toString();
|
||||
|
||||
httpURLConnection.setFixedLengthStreamingMode(requestBody.length());
|
||||
httpURLConnection.setRequestProperty("Content-Type", "application/json");
|
||||
httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com");
|
||||
httpURLConnection.connect();
|
||||
|
||||
try (OutputStream outputStream = httpURLConnection.getOutputStream()) {
|
||||
outputStream.write(requestBody.getBytes(StandardCharsets.US_ASCII));
|
||||
}
|
||||
|
||||
JsonObject jsonObject = microsoftAuthenticator.parseResponseData(httpURLConnection);
|
||||
return new MinecraftToken(jsonObject.get("access_token", JsonString.class).getValue(), jsonObject.get("username", JsonString.class).getValue());
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check ownership from {@link MinecraftToken} and generate {@link MinecraftProfile}
|
||||
*
|
||||
* @param minecraftToken the minecraft token
|
||||
* @return the minecraft profile
|
||||
*/
|
||||
public MinecraftProfile checkOwnership(MinecraftToken minecraftToken) {
|
||||
try {
|
||||
URL url = new URL("https://api.minecraftservices.com/minecraft/profile");
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
|
||||
httpURLConnection.setRequestMethod("GET");
|
||||
|
||||
httpURLConnection.setRequestProperty("Authorization", "Bearer " + minecraftToken.getAccessToken());
|
||||
httpURLConnection.setRequestProperty("Host", "api.minecraftservices.com");
|
||||
httpURLConnection.connect();
|
||||
|
||||
JsonObject jsonObject = parseResponseData(httpURLConnection);
|
||||
|
||||
UUID uuid = generateUUID(jsonObject.get("id", JsonString.class).getValue());
|
||||
String name = jsonObject.get("name", JsonString.class).getValue();
|
||||
List<MinecraftSkin> minecraftSkins = json.fromJson(jsonObject.get("skins", JsonArray.class), List.class, MinecraftSkin.class);
|
||||
List<MinecraftCape> minecraftCapes = json.fromJson(jsonObject.get("capes", JsonArray.class), List.class, MinecraftCape.class);
|
||||
|
||||
return new MinecraftProfile(uuid, name, minecraftSkins, minecraftCapes);
|
||||
} catch (IOException exception) {
|
||||
throw new AuthenticationException(String.format("Authentication error. Request could not be made! Cause: '%s'", exception.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse response data to {@link JsonObject}
|
||||
*
|
||||
* @param httpURLConnection the http url connection
|
||||
* @return the json object
|
||||
* @throws IOException the io exception
|
||||
*/
|
||||
public JsonObject parseResponseData(HttpURLConnection httpURLConnection) throws IOException {
|
||||
BufferedReader bufferedReader;
|
||||
|
||||
if (httpURLConnection.getResponseCode() != 200) {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream()));
|
||||
} else {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
|
||||
}
|
||||
String lines = bufferedReader.lines().collect(Collectors.joining());
|
||||
|
||||
JsonObject jsonObject = json.fromJsonString(lines, JsonObject.class);
|
||||
if (jsonObject.has("error")) {
|
||||
throw new AuthenticationException(String.format("Could not find profile!. Error: '%s'", jsonObject.get("errorMessage", JsonString.class).getValue()));
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate uuid from trimmedUUID
|
||||
*
|
||||
* @param trimmedUUID the trimmed uuid
|
||||
* @return the uuid
|
||||
* @throws IllegalArgumentException the illegal argument exception
|
||||
*/
|
||||
public UUID generateUUID(String trimmedUUID) throws IllegalArgumentException {
|
||||
if (trimmedUUID == null) throw new IllegalArgumentException();
|
||||
StringBuilder builder = new StringBuilder(trimmedUUID.trim());
|
||||
try {
|
||||
builder.insert(20, "-");
|
||||
builder.insert(16, "-");
|
||||
builder.insert(12, "-");
|
||||
builder.insert(8, "-");
|
||||
return UUID.fromString(builder.toString());
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package me.ratsiel.auth.model.mojang;
|
||||
|
||||
/**
|
||||
* The class Minecraft token stores minecraft accessToken and username
|
||||
*/
|
||||
public class MinecraftToken {
|
||||
|
||||
private String accessToken;
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft token.
|
||||
*/
|
||||
public MinecraftToken() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft token.
|
||||
*
|
||||
* @param accessToken the access token
|
||||
* @param username the username
|
||||
*/
|
||||
public MinecraftToken(String accessToken, String username) {
|
||||
this.accessToken = accessToken;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets access token.
|
||||
*
|
||||
* @return the access token
|
||||
*/
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets username.
|
||||
*
|
||||
* @return the username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MinecraftToken{" +
|
||||
"accessToken='" + accessToken + '\'' +
|
||||
", username='" + username + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package me.ratsiel.auth.model.mojang.profile;
|
||||
|
||||
import me.ratsiel.auth.abstracts.TextureVariable;
|
||||
|
||||
/**
|
||||
* The class Minecraft cape stores cape data from {@link me.ratsiel.auth.model.mojang.profile.MinecraftProfile}
|
||||
*/
|
||||
public class MinecraftCape extends TextureVariable {
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft cape.
|
||||
*/
|
||||
public MinecraftCape() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft cape.
|
||||
*
|
||||
* @param id the id
|
||||
* @param state the state
|
||||
* @param url the url
|
||||
* @param alias the alias
|
||||
*/
|
||||
public MinecraftCape(String id, String state, String url, String alias) {
|
||||
super(id, state, url, alias);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package me.ratsiel.auth.model.mojang.profile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The class Minecraft profile stores uuid, username, skins and capes
|
||||
*/
|
||||
public class MinecraftProfile {
|
||||
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
private List<MinecraftSkin> skins;
|
||||
private List<MinecraftCape> capes;
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft profile.
|
||||
*/
|
||||
public MinecraftProfile() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft profile.
|
||||
*
|
||||
* @param uuid the uuid
|
||||
* @param username the username
|
||||
* @param skins the skins
|
||||
* @param capes the capes
|
||||
*/
|
||||
public MinecraftProfile(UUID uuid, String username, List<MinecraftSkin> skins, List<MinecraftCape> capes) {
|
||||
this.uuid = uuid;
|
||||
this.username = username;
|
||||
this.skins = skins;
|
||||
this.capes = capes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets uuid.
|
||||
*
|
||||
* @return the uuid
|
||||
*/
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets username.
|
||||
*
|
||||
* @return the username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets skins.
|
||||
*
|
||||
* @return the skins
|
||||
*/
|
||||
public List<MinecraftSkin> getSkins() {
|
||||
return skins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets capes.
|
||||
*
|
||||
* @return the capes
|
||||
*/
|
||||
public List<MinecraftCape> getCapes() {
|
||||
return capes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MinecraftProfile{" +
|
||||
"uuid=" + uuid +
|
||||
", username='" + username + '\'' +
|
||||
", skins=" + skins +
|
||||
", capes=" + capes +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package me.ratsiel.auth.model.mojang.profile;
|
||||
|
||||
import me.ratsiel.auth.abstracts.TextureVariable;
|
||||
|
||||
/**
|
||||
* The class Minecraft skin stores cape data from {@link me.ratsiel.auth.model.mojang.profile.MinecraftProfile}
|
||||
*/
|
||||
public class MinecraftSkin extends TextureVariable {
|
||||
|
||||
private String variant;
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft skin.
|
||||
*/
|
||||
public MinecraftSkin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft skin.
|
||||
*
|
||||
* @param variant the variant
|
||||
*/
|
||||
public MinecraftSkin(String variant) {
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Minecraft skin.
|
||||
*
|
||||
* @param id the id
|
||||
* @param state the state
|
||||
* @param url the url
|
||||
* @param alias the alias
|
||||
* @param variant the variant
|
||||
*/
|
||||
public MinecraftSkin(String id, String state, String url, String alias, String variant) {
|
||||
super(id, state, url, alias);
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets variant.
|
||||
*
|
||||
* @return the variant
|
||||
*/
|
||||
public String getVariant() {
|
||||
return variant;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MinecraftSkin{" +
|
||||
"id='" + getId() + '\'' +
|
||||
", state='" + getState() + '\'' +
|
||||
", url='" + getUrl() + '\'' +
|
||||
", alias='" + getAlias() + '\'' +
|
||||
"variant='" + variant + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
183
src/main/java/me/ratsiel/json/Json.java
Normal file
183
src/main/java/me/ratsiel/json/Json.java
Normal file
|
@ -0,0 +1,183 @@
|
|||
package me.ratsiel.json;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonHandler;
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
import me.ratsiel.json.model.JsonString;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The type Json.
|
||||
*/
|
||||
public class Json {
|
||||
|
||||
private final JsonGenerator jsonGenerator = new JsonGenerator();
|
||||
private final JsonParser jsonParser = new JsonParser();
|
||||
|
||||
public Json() {
|
||||
registerHandler(UUID.class, new JsonHandler<UUID>() {
|
||||
@Override
|
||||
public UUID serialize(JsonValue jsonValue) {
|
||||
JsonString jsonString = (JsonString) jsonValue;
|
||||
return UUID.fromString(jsonString.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonValue deserialize(UUID value) {
|
||||
return new JsonString(value.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@link String} to {@link JsonValue}.
|
||||
*
|
||||
* @param json the json used to parse
|
||||
* @return the json value is the raw return type
|
||||
*/
|
||||
public JsonValue fromJsonString(String json) {
|
||||
return jsonParser.parse(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@link String} to {@link JsonValue} and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the type of {@link JsonValue}
|
||||
* @param json the input stream is used to parse
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return the value {@link T}
|
||||
*/
|
||||
public <T extends JsonValue> T fromJsonString(String json, Class<T> clazz) {
|
||||
return jsonParser.parse(json, clazz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse {@link File} to {@link JsonValue} and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the type of {@link JsonValue}
|
||||
* @param file the file is used to parse
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return the value {@link T}
|
||||
* @throws FileNotFoundException the file not found exception
|
||||
*/
|
||||
public <T extends JsonValue> T fromFile(File file, Class<T> clazz) throws FileNotFoundException {
|
||||
return clazz.cast(jsonParser.parse(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@link File} to {@link JsonValue}.
|
||||
*
|
||||
* @param file the file used to parse
|
||||
* @return the json value raw return type
|
||||
* @throws FileNotFoundException the file not found exception
|
||||
*/
|
||||
public JsonValue fromFile(File file) throws FileNotFoundException {
|
||||
return jsonParser.parse(new FileInputStream(file));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse {@link InputStream} to {@link JsonValue} and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the type of {@link JsonValue}
|
||||
* @param inputStream the input stream is used to parse
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return the value {@link T}
|
||||
*/
|
||||
public <T extends JsonValue> T parse(InputStream inputStream, Class<T> clazz) {
|
||||
return jsonParser.parse(inputStream, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json value with {@link InputStream}
|
||||
*
|
||||
* @param inputStream the input stream is used to parse
|
||||
* @return the json value is the raw return type
|
||||
*/
|
||||
public JsonValue parse(InputStream inputStream) {
|
||||
return jsonParser.parse(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* To json value.
|
||||
* Parse object of type {@link T} to {@link JsonValue}
|
||||
*
|
||||
* @param <T> the type parameter used to determine value
|
||||
* @param value the value used to parse
|
||||
* @return the json value returns raw type of {@link JsonValue}
|
||||
*/
|
||||
public <T> JsonValue toJson(T value) {
|
||||
return jsonGenerator.toJson(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* From json to list.
|
||||
* Convert {@link JsonValue} to {@link T} and cast with {@link Class<K>}
|
||||
*
|
||||
* @param <T> the type parameter determines object type
|
||||
* @param <K> the type parameter is the class that is used t ocast
|
||||
* @param jsonValue the json value is used to convert
|
||||
* @param listClazz the list clazz is used to cast {@link T}
|
||||
* @param clazz the clazz is used to determine object in {@link List}
|
||||
* @return T is a list with cast {@link Class<T>}
|
||||
*/
|
||||
public <T extends List<K>, K> T fromJson(JsonValue jsonValue, Class<T> listClazz, Class<K> clazz) {
|
||||
return jsonGenerator.fromJson(jsonValue, listClazz, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* From json with cast.
|
||||
* Convert {@link JsonValue} to {@link T}
|
||||
*
|
||||
* @param <T> the type parameter determines type of return object
|
||||
* @param jsonValue the json value is used to convert to {@link T}
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return {@link T} cast with {@link Class<T>}
|
||||
*/
|
||||
public <T> T fromJsonCast(JsonValue jsonValue, Class<T> clazz) {
|
||||
return jsonGenerator.fromJsonCast(jsonValue, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* From json.
|
||||
* Convert {@link JsonValue} to raw object
|
||||
*
|
||||
* @param <T> the type parameter determines type of return object
|
||||
* @param jsonValue the json value is used to convert to {@link Object}
|
||||
* @param clazz the clazz is used create object
|
||||
* @return the object
|
||||
*/
|
||||
public <T> Object fromJson(JsonValue jsonValue, Class<T> clazz) {
|
||||
return jsonGenerator.fromJson(jsonValue, clazz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register handler.
|
||||
* Register a {@link JsonHandler<?>} by {@link Class<?>}
|
||||
*
|
||||
* @param clazz the clazz used to put {@link Class<?>} and {@link JsonHandler<?>} in {@link #jsonGenerator}
|
||||
* @param jsonHandler the json handler is used to insert
|
||||
*/
|
||||
public void registerHandler(Class<?> clazz, JsonHandler<?> jsonHandler) {
|
||||
jsonGenerator.registerHandler(clazz, jsonHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister handler.
|
||||
* Unregister a {@link JsonHandler} by {@link Class<?>}
|
||||
*
|
||||
* @param clazz the clazz used to remove {@link JsonHandler} from {@link #jsonGenerator}
|
||||
*/
|
||||
public void unregisterHandler(Class<?> clazz) {
|
||||
jsonGenerator.unregisterHandler(clazz);
|
||||
}
|
||||
|
||||
}
|
312
src/main/java/me/ratsiel/json/JsonGenerator.java
Normal file
312
src/main/java/me/ratsiel/json/JsonGenerator.java
Normal file
|
@ -0,0 +1,312 @@
|
|||
package me.ratsiel.json;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonHandler;
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
import me.ratsiel.json.model.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The class Json generator is used to parse json to a class or object to json.
|
||||
*/
|
||||
public class JsonGenerator {
|
||||
|
||||
/**
|
||||
* The Handlers is {@link Map} with key {@link Class<?>} and {@link JsonHandler<?>}
|
||||
*/
|
||||
protected final HashMap<Class<?>, JsonHandler<?>> handlers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* To json value.
|
||||
* Parse object of type {@link T} to {@link JsonValue}
|
||||
*
|
||||
* @param <T> the type parameter used to determine value
|
||||
* @param value the value used to parse
|
||||
* @return the json value returns raw type of {@link JsonValue}
|
||||
*/
|
||||
public <T> JsonValue toJson(T value) {
|
||||
JsonValue jsonValue;
|
||||
if (value == null) {
|
||||
jsonValue = new JsonNull();
|
||||
return jsonValue;
|
||||
}
|
||||
|
||||
JsonHandler jsonHandler = getHandler(value.getClass());
|
||||
|
||||
if (jsonHandler != null) {
|
||||
return jsonHandler.deserialize(value);
|
||||
}
|
||||
|
||||
Class<?> clazz = value.getClass();
|
||||
|
||||
if (String.class.isAssignableFrom(clazz)) {
|
||||
jsonValue = new JsonString();
|
||||
((JsonString) jsonValue).setValue((String) value);
|
||||
return jsonValue;
|
||||
} else if (Enum.class.isAssignableFrom(clazz)) {
|
||||
jsonValue = new JsonString();
|
||||
((JsonString) jsonValue).setValue(((Enum) value).name());
|
||||
return jsonValue;
|
||||
} else if (Number.class.isAssignableFrom(clazz)) {
|
||||
jsonValue = new JsonNumber();
|
||||
((JsonNumber) jsonValue).setValue(value.toString());
|
||||
return jsonValue;
|
||||
} else if (Boolean.class.isAssignableFrom(clazz)) {
|
||||
jsonValue = new JsonBoolean();
|
||||
((JsonBoolean) jsonValue).setValue((Boolean) value);
|
||||
return jsonValue;
|
||||
} else if (List.class.isAssignableFrom(clazz)) {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
List<?> list = (List<?>) value;
|
||||
for (Object listValue : list) {
|
||||
jsonArray.add(toJson(listValue));
|
||||
}
|
||||
return jsonArray;
|
||||
} else if (Map.class.isAssignableFrom(clazz)) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
Map<?, ?> map = (Map<?, ?>) value;
|
||||
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
Object mapValue = entry.getValue();
|
||||
if (key == null) {
|
||||
jsonObject.add("null", toJson(mapValue));
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<?> keyClazz = key.getClass();
|
||||
if (String.class.isAssignableFrom(keyClazz)
|
||||
|| Number.class.isAssignableFrom(keyClazz)
|
||||
|| Boolean.class.isAssignableFrom(keyClazz)) {
|
||||
jsonObject.add(String.valueOf(key), toJson(mapValue));
|
||||
} else if (Enum.class.isAssignableFrom(keyClazz)) {
|
||||
jsonObject.add(((Enum) key).name(), toJson(mapValue));
|
||||
}
|
||||
|
||||
}
|
||||
return jsonObject;
|
||||
} else {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
if (hasSuperclass(clazz)) {
|
||||
for (Field declaredField : clazz.getSuperclass().getDeclaredFields()) {
|
||||
populateFields(value, jsonObject, declaredField);
|
||||
}
|
||||
}
|
||||
|
||||
for (Field declaredField : clazz.getDeclaredFields()) {
|
||||
populateFields(value, jsonObject, declaredField);
|
||||
}
|
||||
|
||||
jsonValue = jsonObject;
|
||||
}
|
||||
|
||||
|
||||
return jsonValue;
|
||||
}
|
||||
|
||||
private <T> void populateFields(T value, JsonObject jsonObject, Field declaredField) {
|
||||
if(declaredField.getModifiers() == Modifier.STATIC) return;
|
||||
|
||||
declaredField.setAccessible(true);
|
||||
try {
|
||||
JsonValue transformedValue = toJson(declaredField.get(value));
|
||||
transformedValue.setKey(declaredField.getName());
|
||||
|
||||
jsonObject.add(transformedValue);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* From json to list.
|
||||
* Convert {@link JsonValue} to {@link T} and cast with {@link Class<K>}
|
||||
*
|
||||
* @param <T> the type parameter determines object type
|
||||
* @param <K> the type parameter is the class that is used t ocast
|
||||
* @param jsonValue the json value is used to convert
|
||||
* @param listClazz the list clazz is used to cast {@link T}
|
||||
* @param clazz the clazz is used to determine object in {@link List}
|
||||
* @return T is a list with cast {@link Class<T>}
|
||||
*/
|
||||
public <T extends List<K>, K> T fromJson(JsonValue jsonValue, Class<T> listClazz, Class<K> clazz) {
|
||||
return listClazz.cast(fromJson(null, jsonValue, clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* From json with cast.
|
||||
* Convert {@link JsonValue} to {@link T}
|
||||
*
|
||||
* @param <T> the type parameter determines type of return object
|
||||
* @param jsonValue the json value is used to convert to {@link T}
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return {@link T} cast with {@link Class<T>}
|
||||
*/
|
||||
public <T> T fromJsonCast(JsonValue jsonValue, Class<T> clazz) {
|
||||
return clazz.cast(fromJson(null, jsonValue, clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* From json.
|
||||
* Convert {@link JsonValue} to raw object
|
||||
*
|
||||
* @param <T> the type parameter determines type of return object
|
||||
* @param jsonValue the json value is used to convert to {@link Object}
|
||||
* @param clazz the clazz is used create object
|
||||
* @return the object
|
||||
*/
|
||||
public <T> Object fromJson(JsonValue jsonValue, Class<T> clazz) {
|
||||
return fromJson(null, jsonValue, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* From json.
|
||||
* Convert {@link JsonValue} to raw object
|
||||
*
|
||||
* @param <T> the type parameter determines type of return object
|
||||
* @param key the key is used to get a value out of {@link JsonObject}
|
||||
* @param jsonValue the json value is used to convert to {@link Object}
|
||||
* @param clazz the clazz is used create object
|
||||
* @return the object
|
||||
*/
|
||||
public <T> Object fromJson(String key, JsonValue jsonValue, Class<T> clazz) {
|
||||
JsonHandler jsonHandler = getHandler(clazz);
|
||||
|
||||
if (jsonValue instanceof JsonString) {
|
||||
if (jsonHandler != null) {
|
||||
return jsonHandler.serialize(jsonValue);
|
||||
}
|
||||
|
||||
return clazz.cast(((JsonString) jsonValue).getValue());
|
||||
} else if (jsonValue instanceof JsonNumber) {
|
||||
|
||||
if (jsonHandler != null) {
|
||||
return jsonHandler.serialize(jsonValue);
|
||||
}
|
||||
|
||||
return ((JsonNumber) jsonValue).getNumber(clazz);
|
||||
} else if (jsonValue instanceof JsonBoolean) {
|
||||
|
||||
if (jsonHandler != null) {
|
||||
return jsonHandler.serialize(jsonValue);
|
||||
}
|
||||
|
||||
return clazz.cast(((JsonBoolean) jsonValue).isValue());
|
||||
} else if (jsonValue instanceof JsonNull) {
|
||||
|
||||
if (jsonHandler != null) {
|
||||
return jsonHandler.serialize(jsonValue);
|
||||
}
|
||||
|
||||
return null;
|
||||
} else if (jsonValue instanceof JsonObject) {
|
||||
if (key != null) {
|
||||
return fromJson(((JsonObject) jsonValue).get(key), clazz);
|
||||
} else {
|
||||
try {
|
||||
T object = clazz.newInstance();
|
||||
|
||||
if (jsonHandler != null) {
|
||||
return jsonHandler.serialize(jsonValue);
|
||||
}
|
||||
|
||||
Class<?> objectClazz = object.getClass();
|
||||
|
||||
if (hasSuperclass(objectClazz)) {
|
||||
for (Field declaredField : objectClazz.getSuperclass().getDeclaredFields()) {
|
||||
declaredField.setAccessible(true);
|
||||
declaredField.set(object, fromJson(declaredField.getName(), jsonValue, declaredField.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
for (Field declaredField : objectClazz.getDeclaredFields()) {
|
||||
declaredField.setAccessible(true);
|
||||
declaredField.set(object, fromJson(declaredField.getName(), jsonValue, declaredField.getType()));
|
||||
}
|
||||
|
||||
return object;
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (jsonValue instanceof JsonArray) {
|
||||
List list = new ArrayList();
|
||||
((JsonArray) jsonValue).loop((integer, listValue) -> {
|
||||
list.add(fromJson(listValue, clazz));
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has superclass boolean.
|
||||
* Checks if given class has a superclass
|
||||
*
|
||||
* @param <T> the type parameter determines type of class used in class
|
||||
* @param clazz the clazz is used to check
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public <T> boolean hasSuperclass(Class<T> clazz) {
|
||||
return clazz.getSuperclass() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register handler.
|
||||
* Register a {@link JsonHandler<?>} by {@link Class<?>}
|
||||
*
|
||||
* @param clazz the clazz used to put {@link Class<?>} and {@link JsonHandler<?>} in {@link #handlers}
|
||||
* @param jsonHandler the json handler is used to insert
|
||||
*/
|
||||
public void registerHandler(Class<?> clazz, JsonHandler<?> jsonHandler) {
|
||||
if (!isRegistered(clazz)) {
|
||||
handlers.put(clazz, jsonHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister handler.
|
||||
* Unregister a {@link JsonHandler} by {@link Class<?>}
|
||||
*
|
||||
* @param clazz the clazz used to remove {@link JsonHandler} from {@link #handlers}
|
||||
*/
|
||||
public void unregisterHandler(Class<?> clazz) {
|
||||
if (isRegistered(clazz)) {
|
||||
handlers.remove(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets handler from {@link #handlers}.
|
||||
*
|
||||
* @param clazz the clazz used to get {@link JsonHandler<?>} from {@link #handlers}
|
||||
* @return the handler null or {@link JsonHandler<?>}
|
||||
*/
|
||||
public JsonHandler<?> getHandler(Class<?> clazz) {
|
||||
if (!isRegistered(clazz)) return null;
|
||||
|
||||
return handlers.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is registered boolean.
|
||||
* Check if {@link JsonHandler<?>} is registered in {@link #handlers}
|
||||
*
|
||||
* @param clazz the clazz used to get {@link JsonHandler<?>}
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isRegistered(Class<?> clazz) {
|
||||
return handlers.containsKey(clazz);
|
||||
}
|
||||
|
||||
}
|
531
src/main/java/me/ratsiel/json/JsonParser.java
Normal file
531
src/main/java/me/ratsiel/json/JsonParser.java
Normal file
|
@ -0,0 +1,531 @@
|
|||
package me.ratsiel.json;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
import me.ratsiel.json.model.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* The class Json parser is used to parse a {@link String} or a {@link File} to {@link JsonValue}
|
||||
*/
|
||||
public class JsonParser {
|
||||
|
||||
private char[] jsonBuffer;
|
||||
private int jsonBufferPosition = 0;
|
||||
|
||||
/**
|
||||
* Parse {@link InputStream} to {@link JsonValue} and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the type of {@link JsonValue}
|
||||
* @param inputStream the input stream is used to parse
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return the value {@link T}
|
||||
*/
|
||||
public <T extends JsonValue> T parse(InputStream inputStream, Class<T> clazz) {
|
||||
return clazz.cast(parse(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json value with {@link InputStream}
|
||||
*
|
||||
* @param inputStream the input stream is used to parse
|
||||
* @return the json value is the raw return type
|
||||
*/
|
||||
public JsonValue parse(InputStream inputStream) {
|
||||
try {
|
||||
prepareParser(inputStream);
|
||||
} catch (IOException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
skipWhiteSpace();
|
||||
switch (peekChar()) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '.':
|
||||
case 'E':
|
||||
case 'e':
|
||||
case '+':
|
||||
case '-': {
|
||||
return parseJsonNumber();
|
||||
}
|
||||
case 'f':
|
||||
case 't': {
|
||||
return parseJsonBoolean();
|
||||
}
|
||||
case 'n': {
|
||||
return parseJsonNull();
|
||||
}
|
||||
case '"': {
|
||||
return parseJsonString();
|
||||
}
|
||||
case '{': {
|
||||
JsonObject jsonObject = parseJsonObject();
|
||||
jsonBuffer = null;
|
||||
jsonBufferPosition = 0;
|
||||
return jsonObject;
|
||||
}
|
||||
case '[': {
|
||||
JsonArray jsonArray = parseJsonArray();
|
||||
jsonBuffer = null;
|
||||
jsonBufferPosition = 0;
|
||||
return jsonArray;
|
||||
}
|
||||
default: {
|
||||
throw new RuntimeException("Could not parse file to Json!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse {@link String} to {@link JsonValue} and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the type of {@link JsonValue}
|
||||
* @param json the input stream is used to parse
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return the value {@link T}
|
||||
*/
|
||||
public <T extends JsonValue> T parse(String json, Class<T> clazz) {
|
||||
return clazz.cast(parse(json));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@link String} to {@link JsonValue}.
|
||||
*
|
||||
* @param json the json used to parse
|
||||
* @return the json value is the raw return type
|
||||
*/
|
||||
public JsonValue parse(String json) {
|
||||
return parse(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse {@link File} to {@link JsonValue} and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the type of {@link JsonValue}
|
||||
* @param file the file is used to parse
|
||||
* @param clazz the clazz is used to cast {@link T}
|
||||
* @return the value {@link T}
|
||||
* @throws FileNotFoundException the file not found exception
|
||||
*/
|
||||
public <T extends JsonValue> T parse(File file, Class<T> clazz) throws FileNotFoundException {
|
||||
return clazz.cast(parse(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse {@link File} to {@link JsonValue}.
|
||||
*
|
||||
* @param file the file used to parse
|
||||
* @return the json value raw return type
|
||||
* @throws FileNotFoundException the file not found exception
|
||||
*/
|
||||
public JsonValue parse(File file) throws FileNotFoundException {
|
||||
return parse(new FileInputStream(file));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare parser to parse given input to {@link JsonValue}.
|
||||
*
|
||||
* @param inputStream the input stream is used to parse
|
||||
* @throws IOException the io exception
|
||||
*/
|
||||
public void prepareParser(InputStream inputStream) throws IOException {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
stringBuilder.append(line).append("\n");
|
||||
}
|
||||
|
||||
jsonBuffer = stringBuilder.toString().toCharArray();
|
||||
bufferedReader.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse char from {@link #jsonBuffer} and increase {@link #jsonBufferPosition}
|
||||
*
|
||||
* @return the char
|
||||
*/
|
||||
public char parseChar() {
|
||||
try {
|
||||
return jsonBuffer[jsonBufferPosition++];
|
||||
} catch (IndexOutOfBoundsException exception) {
|
||||
return (char) -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek char with {@link #parseChar()} and revoke {@link #jsonBufferPosition}
|
||||
*
|
||||
* @return the char
|
||||
*/
|
||||
public char peekChar() {
|
||||
char currentChar = parseChar();
|
||||
jsonBufferPosition--;
|
||||
return currentChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip white space.
|
||||
*/
|
||||
public void skipWhiteSpace() {
|
||||
while (isWhiteSpace()) {
|
||||
parseChar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse json object json object.
|
||||
* Iterates through chars and construct json object.
|
||||
*
|
||||
* @return the json object
|
||||
*/
|
||||
public JsonObject parseJsonObject() {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
skipWhiteSpace();
|
||||
// Skip '{'
|
||||
parseChar();
|
||||
|
||||
char currentChar = peekChar();
|
||||
while (currentChar != '}') {
|
||||
skipWhiteSpace();
|
||||
|
||||
// Check the next char and handle it!
|
||||
switch (peekChar()) {
|
||||
case '"': {
|
||||
|
||||
String key = parseJsonString().getValue();
|
||||
|
||||
skipWhiteSpace();
|
||||
// Skip ':'
|
||||
currentChar = parseChar();
|
||||
skipWhiteSpace();
|
||||
|
||||
switch (peekChar()) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '.':
|
||||
case 'E':
|
||||
case 'e':
|
||||
case '+':
|
||||
case '-': {
|
||||
JsonNumber jsonNumber = parseJsonNumber();
|
||||
jsonNumber.setKey(key);
|
||||
jsonObject.add(jsonNumber);
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 't': {
|
||||
JsonBoolean jsonBoolean = parseJsonBoolean();
|
||||
jsonBoolean.setKey(key);
|
||||
jsonObject.add(jsonBoolean);
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
JsonNull jsonNull = parseJsonNull();
|
||||
jsonNull.setKey(key);
|
||||
jsonObject.add(jsonNull);
|
||||
break;
|
||||
}
|
||||
case '"': {
|
||||
JsonString jsonString = parseJsonString();
|
||||
jsonString.setKey(key);
|
||||
jsonObject.add(jsonString);
|
||||
break;
|
||||
}
|
||||
case '{': {
|
||||
JsonObject object = parseJsonObject();
|
||||
object.setKey(key);
|
||||
jsonObject.add(object);
|
||||
break;
|
||||
}
|
||||
case '[': {
|
||||
JsonArray jsonArray = parseJsonArray();
|
||||
jsonArray.setKey(key);
|
||||
jsonObject.add(jsonArray);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case '}':
|
||||
case ',': {
|
||||
currentChar = parseChar();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new RuntimeException(String.format("Could not parse JsonObject stuck at Index: %s as Char: %s", jsonBufferPosition, jsonBuffer[jsonBufferPosition]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json array json array.
|
||||
* Iterates through chars and construct json array.
|
||||
*
|
||||
* @return the json array
|
||||
*/
|
||||
public JsonArray parseJsonArray() {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
|
||||
skipWhiteSpace();
|
||||
// Skip '['
|
||||
parseChar();
|
||||
|
||||
char currentChar = peekChar();
|
||||
|
||||
|
||||
while (currentChar != ']') {
|
||||
skipWhiteSpace();
|
||||
|
||||
// Check the next char and handle it!
|
||||
switch (peekChar()) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '.':
|
||||
case 'E':
|
||||
case 'e':
|
||||
case '+':
|
||||
case '-': {
|
||||
jsonArray.add(parseJsonNumber());
|
||||
break;
|
||||
}
|
||||
case '"': {
|
||||
jsonArray.add(parseJsonString());
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 't': {
|
||||
jsonArray.add(parseJsonBoolean());
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
jsonArray.add(parseJsonNull());
|
||||
break;
|
||||
}
|
||||
case '{': {
|
||||
jsonArray.add(parseJsonObject());
|
||||
break;
|
||||
}
|
||||
case '[': {
|
||||
jsonArray.add(parseJsonArray());
|
||||
break;
|
||||
}
|
||||
case ']':
|
||||
case ',': {
|
||||
currentChar = parseChar();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new RuntimeException(String.format("Could not parse JsonArray stuck at Index: %s as Char: %s", jsonBufferPosition, jsonBuffer[jsonBufferPosition]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json string.
|
||||
* Iterates through chars and construct json string.
|
||||
*
|
||||
* @return the json string
|
||||
*/
|
||||
public JsonString parseJsonString() {
|
||||
JsonString jsonString = new JsonString();
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
skipWhiteSpace();
|
||||
|
||||
|
||||
// Take the first '"'
|
||||
parseChar();
|
||||
|
||||
char currentChar = parseChar();
|
||||
|
||||
while (currentChar != '"') {
|
||||
// Check if in a string is an escape char
|
||||
if (currentChar == '\\') {
|
||||
stringBuilder.append(currentChar);
|
||||
currentChar = parseChar();
|
||||
}
|
||||
|
||||
stringBuilder.append(currentChar);
|
||||
currentChar = parseChar();
|
||||
}
|
||||
|
||||
skipWhiteSpace();
|
||||
|
||||
jsonString.setValue(stringBuilder.toString());
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json null.
|
||||
* Iterates through chars and check if json null is given.
|
||||
*
|
||||
* @return the json null
|
||||
*/
|
||||
public JsonNull parseJsonNull() {
|
||||
char currentChar = parseChar();
|
||||
if (currentChar == 'n' && isNextChar('u', 0) && isNextChar('l', 1) && isNextChar('l', 2)) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
jsonBufferPosition++;
|
||||
}
|
||||
return new JsonNull();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json boolean.
|
||||
* Iterates through chars and check if json boolean is given.
|
||||
*
|
||||
* @return the json boolean
|
||||
*/
|
||||
public JsonBoolean parseJsonBoolean() {
|
||||
char currentChar = parseChar();
|
||||
JsonBoolean jsonBoolean = null;
|
||||
if (currentChar == 't' && isNextChar('r', 0) && isNextChar('u', 1) && isNextChar('e', 2)) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
jsonBufferPosition++;
|
||||
}
|
||||
jsonBoolean = new JsonBoolean();
|
||||
jsonBoolean.setValue(true);
|
||||
} else if (currentChar == 'f' && isNextChar('a', 0) && isNextChar('l', 1) && isNextChar('s', 2) && isNextChar('e', 3)) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
jsonBufferPosition++;
|
||||
}
|
||||
jsonBoolean = new JsonBoolean();
|
||||
jsonBoolean.setValue(false);
|
||||
}
|
||||
return jsonBoolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse json number.
|
||||
* Iterates through chars and check if json number is given.
|
||||
*
|
||||
* @return the json number
|
||||
*/
|
||||
public JsonNumber parseJsonNumber() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
char currentChar = parseChar();
|
||||
|
||||
while (isNumber(currentChar)) {
|
||||
stringBuilder.append(currentChar);
|
||||
|
||||
currentChar = parseChar();
|
||||
}
|
||||
|
||||
jsonBufferPosition--;
|
||||
|
||||
JsonNumber jsonNumber = new JsonNumber();
|
||||
jsonNumber.setValue(stringBuilder.toString());
|
||||
|
||||
return jsonNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is white space boolean.
|
||||
* Check if current char in {@link #jsonBuffer} is a whitespace
|
||||
*
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isWhiteSpace() {
|
||||
char currentChar = jsonBuffer[jsonBufferPosition];
|
||||
return currentChar == ' ' || currentChar == '\t' || currentChar == '\r' || currentChar == '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is next char boolean.
|
||||
* Check if next char is given char by position
|
||||
*
|
||||
* @param currentChar the current char is the char that is going to be checked
|
||||
* @param position the position used to get char at position from {@link #jsonBuffer}
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isNextChar(char currentChar, int position) {
|
||||
for (int i = 0; i < position; i++) {
|
||||
parseChar();
|
||||
}
|
||||
char nextChar = peekChar();
|
||||
for (int i = 0; i < position; i++) {
|
||||
jsonBufferPosition--;
|
||||
}
|
||||
return nextChar == currentChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is number boolean.
|
||||
* Check if current char is a number
|
||||
* @param currentChar the current char is used to check
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isNumber(char currentChar) {
|
||||
char[] numberElements = new char[]{
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'.',
|
||||
'E',
|
||||
'e',
|
||||
'+',
|
||||
'-'
|
||||
};
|
||||
|
||||
for (char listChar : numberElements) {
|
||||
if (listChar == currentChar) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
26
src/main/java/me/ratsiel/json/abstracts/JsonHandler.java
Normal file
26
src/main/java/me/ratsiel/json/abstracts/JsonHandler.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package me.ratsiel.json.abstracts;
|
||||
|
||||
/**
|
||||
* The abstract class {@link JsonHandler} with generic type {@link T} is used to serialize and deserialize an object
|
||||
*
|
||||
* @param <T> the type parameter type of object which is going to be serialized or deserialized.
|
||||
*/
|
||||
public abstract class JsonHandler<T> {
|
||||
|
||||
/**
|
||||
* Serialize {@link JsonValue} to object of type {@link T}
|
||||
*
|
||||
* @param jsonValue the json value can be a value like something {@link me.ratsiel.json.model.JsonObject} or {@link me.ratsiel.json.model.JsonArray}
|
||||
* @return the t
|
||||
*/
|
||||
public abstract T serialize(JsonValue jsonValue);
|
||||
|
||||
/**
|
||||
* Deserialize {@link T} to {@link JsonValue}
|
||||
*
|
||||
* @param value the value is an object of {@link T}
|
||||
* @return the json value is the deserialized value of {@link T}
|
||||
*/
|
||||
public abstract JsonValue deserialize(T value);
|
||||
|
||||
}
|
80
src/main/java/me/ratsiel/json/abstracts/JsonValue.java
Normal file
80
src/main/java/me/ratsiel/json/abstracts/JsonValue.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
package me.ratsiel.json.abstracts;
|
||||
|
||||
/**
|
||||
* The class {@link JsonValue} is an upper class for Json values like {@link me.ratsiel.json.model.JsonObject}
|
||||
*/
|
||||
public abstract class JsonValue {
|
||||
|
||||
private int intend = 0;
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* Instantiates a new Json value.
|
||||
*/
|
||||
public JsonValue() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json value.
|
||||
*
|
||||
* @param key the key is used to find a document in {@link me.ratsiel.json.model.JsonObject}
|
||||
*/
|
||||
public JsonValue(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create space string.
|
||||
* Used to generate the spaces when a object of type {@link JsonValue} is used with {@link #toString()}
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
protected String createSpace() {
|
||||
StringBuilder spaceBuilder = new StringBuilder();
|
||||
for (int i = 0; i < intend; i++) {
|
||||
spaceBuilder.append(" ");
|
||||
}
|
||||
return spaceBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
/**
|
||||
* Gets key.
|
||||
*
|
||||
* @return key the key is used to find a document in {@link me.ratsiel.json.model.JsonObject}
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets key.
|
||||
*
|
||||
* @param key the key is used to find a document in {@link me.ratsiel.json.model.JsonObject}
|
||||
*/
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets intend.
|
||||
*
|
||||
* @return the intend used to calculate free space in method {@link #createSpace()}
|
||||
*/
|
||||
public int getIntend() {
|
||||
return intend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets intend.
|
||||
*
|
||||
* @param intend the intend used to calculate ree space in method {@link #createSpace()}
|
||||
*/
|
||||
public void setIntend(int intend) {
|
||||
this.intend = intend;
|
||||
}
|
||||
|
||||
}
|
70
src/main/java/me/ratsiel/json/interfaces/IListable.java
Normal file
70
src/main/java/me/ratsiel/json/interfaces/IListable.java
Normal file
|
@ -0,0 +1,70 @@
|
|||
package me.ratsiel.json.interfaces;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The interface Listable.
|
||||
* Used to implement functions like {@link #loop(Consumer)} or {@link #get(int)}
|
||||
*
|
||||
* @param <T> the type parameter determines generic type of value that can be get or added from a list
|
||||
*/
|
||||
public interface IListable<T> {
|
||||
|
||||
/**
|
||||
* Size int.
|
||||
*
|
||||
* @return the int determines the size of given list
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Add value to something.
|
||||
*
|
||||
* @param value the value is going to be add to a list or something else
|
||||
*/
|
||||
void add(T value);
|
||||
|
||||
/**
|
||||
* Add value to something where a index is needed.
|
||||
*
|
||||
* @param index the index is the position identifier of the object
|
||||
* @param value the value is going to be add to a list or something else
|
||||
*/
|
||||
void add(int index, T value);
|
||||
|
||||
/**
|
||||
* Get a value of type {@link T} by its index and cast it with {@link Class<T>}.
|
||||
*
|
||||
* @param index the index is the position of the object
|
||||
* @param clazz the clazz is the type of object
|
||||
* @return object of type {@link T}
|
||||
*/
|
||||
T get(int index, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Get a value of type {@link T} by its index.
|
||||
*
|
||||
* @param index the index is the position of the object
|
||||
* @return object of type {@link T}
|
||||
*/
|
||||
T get(int index);
|
||||
|
||||
/**
|
||||
* Loop is used to iterate through a {@link java.util.List} or an {@link java.util.Iterator}
|
||||
*
|
||||
* @param consumer the consumer accepts values from {@link java.util.List}
|
||||
*/
|
||||
void loop(Consumer<JsonValue> consumer);
|
||||
|
||||
/**
|
||||
* Loop is used to iterate through a {@link java.util.List} or an {@link java.util.Iterator}
|
||||
*
|
||||
* @param consumer the consumer the consumer accepts values and indexes from {@link java.util.List}
|
||||
*/
|
||||
void loop(BiConsumer<Integer, JsonValue> consumer);
|
||||
|
||||
|
||||
}
|
147
src/main/java/me/ratsiel/json/model/JsonArray.java
Normal file
147
src/main/java/me/ratsiel/json/model/JsonArray.java
Normal file
|
@ -0,0 +1,147 @@
|
|||
package me.ratsiel.json.model;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
import me.ratsiel.json.interfaces.IListable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The class Json array is used to store objects of type {@link JsonValue} in {@link #values}
|
||||
*/
|
||||
public class JsonArray extends JsonValue implements IListable<JsonValue> {
|
||||
|
||||
|
||||
/**
|
||||
* The Values is a list which is used by the {@link IListable}
|
||||
*/
|
||||
protected final List<JsonValue> values = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Instantiates a new Json array.
|
||||
*/
|
||||
public JsonArray() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json array.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
*/
|
||||
public JsonArray(String key) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
String space = createSpace();
|
||||
|
||||
stringBuilder.append(space);
|
||||
if (getKey() != null && !getKey().isEmpty()) {
|
||||
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
|
||||
}
|
||||
|
||||
stringBuilder.append("[");
|
||||
loop((integer, jsonValue) -> {
|
||||
jsonValue.setIntend(getIntend() + 2);
|
||||
stringBuilder.append("\n");
|
||||
if(!(integer == size() - 1)) {
|
||||
stringBuilder.append(jsonValue).append(",");
|
||||
} else {
|
||||
stringBuilder.append(jsonValue);
|
||||
}
|
||||
});
|
||||
stringBuilder.append("\n").append(space).append("]");
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(JsonValue value) {
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, JsonValue value) {
|
||||
values.set(index, value);
|
||||
}
|
||||
|
||||
public void addString(String value) {
|
||||
JsonString jsonString = new JsonString(value);
|
||||
this.add(jsonString);
|
||||
}
|
||||
|
||||
public void addBoolean(boolean value) {
|
||||
JsonBoolean jsonBoolean = new JsonBoolean(value);
|
||||
this.add(jsonBoolean);
|
||||
}
|
||||
|
||||
public void addByte(byte value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addInteger(int value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addShort(short value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addDouble(double value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addFloat(float value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addLong(long value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonValue get(int index, Class<JsonValue> clazz) {
|
||||
return clazz.cast(get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonValue get(int index) {
|
||||
return values.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop(Consumer<JsonValue> consumer) {
|
||||
for (JsonValue value : values) {
|
||||
consumer.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop(BiConsumer<Integer, JsonValue> consumer) {
|
||||
for (int index = 0; index < values.size(); index++) {
|
||||
JsonValue jsonValue = values.get(index);
|
||||
consumer.accept(index, jsonValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
77
src/main/java/me/ratsiel/json/model/JsonBoolean.java
Normal file
77
src/main/java/me/ratsiel/json/model/JsonBoolean.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
package me.ratsiel.json.model;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
|
||||
/**
|
||||
* The class Json boolean stores a boolean.
|
||||
*/
|
||||
public class JsonBoolean extends JsonValue {
|
||||
|
||||
/**
|
||||
* The Value is the given boolean
|
||||
*/
|
||||
public boolean value;
|
||||
|
||||
/**
|
||||
* Instantiates a new Json boolean.
|
||||
*/
|
||||
public JsonBoolean() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json boolean.
|
||||
*
|
||||
* @param value the value is the given boolean that is set to {@link #value}
|
||||
*/
|
||||
public JsonBoolean(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json boolean.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @param value the value is the given boolean that is set to {@link #value}
|
||||
*/
|
||||
public JsonBoolean(String key, boolean value) {
|
||||
super(key);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String space = createSpace();
|
||||
|
||||
stringBuilder.append(space);
|
||||
if (getKey() != null && !getKey().isEmpty()) {
|
||||
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
|
||||
}
|
||||
stringBuilder.append(isValue());
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is value boolean.
|
||||
*
|
||||
* @return the boolean value is the stored at {@link #value}
|
||||
*/
|
||||
public boolean isValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value.
|
||||
*
|
||||
* @param value the value is the value {@link #value}
|
||||
*/
|
||||
public void setValue(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
53
src/main/java/me/ratsiel/json/model/JsonNull.java
Normal file
53
src/main/java/me/ratsiel/json/model/JsonNull.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package me.ratsiel.json.model;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
|
||||
/**
|
||||
* The class Json null store a null value.
|
||||
*/
|
||||
public class JsonNull extends JsonValue {
|
||||
|
||||
/**
|
||||
* The Value is a final value because null is null!
|
||||
*/
|
||||
protected final String value = "null";
|
||||
|
||||
/**
|
||||
* Instantiates a new Json null.
|
||||
*/
|
||||
public JsonNull() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json null.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
*/
|
||||
public JsonNull(String key) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String space = createSpace();
|
||||
|
||||
|
||||
stringBuilder.append(space);
|
||||
if (getKey() != null && !getKey().isEmpty()) {
|
||||
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
|
||||
}
|
||||
stringBuilder.append("null");
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value.
|
||||
*
|
||||
* @return the value is the stored at {@link #value}
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
275
src/main/java/me/ratsiel/json/model/JsonNumber.java
Normal file
275
src/main/java/me/ratsiel/json/model/JsonNumber.java
Normal file
|
@ -0,0 +1,275 @@
|
|||
package me.ratsiel.json.model;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* The class Json number stores a string that can be cast to a number.
|
||||
*/
|
||||
public class JsonNumber extends JsonValue {
|
||||
|
||||
/**
|
||||
* The Value is a string that can be cast to a number.
|
||||
*/
|
||||
protected String value;
|
||||
|
||||
/**
|
||||
* Instantiates a new Json number.
|
||||
*/
|
||||
public JsonNumber() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new Json number.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @param value the value is the given string that is set to {@link #value}
|
||||
*/
|
||||
public JsonNumber(String key, String value) {
|
||||
super(key);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json number.
|
||||
*
|
||||
* @param value the value
|
||||
*/
|
||||
public JsonNumber(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
String space = createSpace();
|
||||
|
||||
stringBuilder.append(space);
|
||||
if (getKey() != null && !getKey().isEmpty()) {
|
||||
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
|
||||
}
|
||||
stringBuilder.append(getValue());
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets value.
|
||||
*
|
||||
* @return the value the value is the given string that is set to {@link #value}
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value.
|
||||
*
|
||||
* @param value the value is set to {@link #value}
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte value byte.
|
||||
* Convert {@link #value} to {@link Byte}
|
||||
*
|
||||
* @return the byte converted value
|
||||
*/
|
||||
public byte byteValue() {
|
||||
return getBigDecimal().byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Int value int.
|
||||
* Convert {@link #value} to {@link Integer}
|
||||
*
|
||||
* @return the int converted value
|
||||
*/
|
||||
public int intValue() {
|
||||
return getBigDecimal().intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Short value short.
|
||||
* Convert {@link #value} to {@link Short}
|
||||
*
|
||||
* @return the short converted value
|
||||
*/
|
||||
public short shortValue() {
|
||||
return getBigDecimal().shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Double value double.
|
||||
* Convert {@link #value} to {@link Double}
|
||||
*
|
||||
* @return the double converted value
|
||||
*/
|
||||
public double doubleValue() {
|
||||
return getBigDecimal().doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Float value float.
|
||||
* Convert {@link #value} to {@link Float}
|
||||
*
|
||||
* @return the float converted value
|
||||
*/
|
||||
public float floatValue() {
|
||||
return getBigDecimal().floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Long value long.
|
||||
* Convert {@link #value} to {@link Long}
|
||||
*
|
||||
* @return the long converted value
|
||||
*/
|
||||
public long longValue() {
|
||||
return getBigDecimal().longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number determined by given class {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter determines the given number
|
||||
* @param clazz the clazz used to use correct number.
|
||||
* @return the number object of type {@link Number}
|
||||
*/
|
||||
public <T> Object getNumber(Class<T> clazz) {
|
||||
|
||||
if (clazz.equals(Byte.class) || clazz.equals(byte.class)) {
|
||||
return byteValue();
|
||||
} else if (clazz.equals(Integer.class) || clazz.equals(int.class)) {
|
||||
return intValue();
|
||||
} else if (clazz.equals(Short.class) || clazz.equals(short.class)) {
|
||||
return shortValue();
|
||||
} else if (clazz.equals(Double.class) || clazz.equals(double.class)) {
|
||||
return doubleValue();
|
||||
} else if (clazz.equals(Float.class) || clazz.equals(float.class)) {
|
||||
return floatValue();
|
||||
} else if (clazz.equals(Long.class) || clazz.equals(long.class)) {
|
||||
return longValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets big decimal.
|
||||
*
|
||||
* @return the big decimal created by {@link #value}
|
||||
*/
|
||||
public BigDecimal getBigDecimal() {
|
||||
return new BigDecimal(getValue());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is numeric boolean.
|
||||
* Check if given string is a number
|
||||
*
|
||||
* @param value the value is used to check
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isNumeric(String value) {
|
||||
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
boolean isNumber = value.matches("[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)");
|
||||
|
||||
if (isNumber) {
|
||||
String testValue;
|
||||
|
||||
if (isInteger(value)) {
|
||||
int integerValue = intValue();
|
||||
|
||||
testValue = String.valueOf(integerValue);
|
||||
} else if (isDouble(value)) {
|
||||
double doubleValue = doubleValue();
|
||||
|
||||
|
||||
if (doubleValue > Double.MAX_VALUE || doubleValue < Double.MIN_EXPONENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
testValue = String.valueOf(Math.round(doubleValue));
|
||||
} else if (isFloat(value)) {
|
||||
float floatValue = floatValue();
|
||||
|
||||
if (floatValue > Float.MAX_VALUE || floatValue < Float.MIN_EXPONENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
testValue = String.valueOf(Math.round(floatValue));
|
||||
} else {
|
||||
testValue = value;
|
||||
}
|
||||
|
||||
try {
|
||||
Long.parseLong(testValue);
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return isNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is float boolean.
|
||||
* Check if given string is a float
|
||||
*
|
||||
* @param value the value is used to check
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isFloat(String value) {
|
||||
try {
|
||||
Float.parseFloat(value);
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is integer boolean.
|
||||
* Check if given string is a integer
|
||||
*
|
||||
* @param value the value is used to check
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isInteger(String value) {
|
||||
try {
|
||||
Integer.parseInt(value);
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is double boolean.
|
||||
* Check if given string is a double
|
||||
*
|
||||
* @param value the value is used to check
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean isDouble(String value) {
|
||||
try {
|
||||
Double.parseDouble(value);
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
215
src/main/java/me/ratsiel/json/model/JsonObject.java
Normal file
215
src/main/java/me/ratsiel/json/model/JsonObject.java
Normal file
|
@ -0,0 +1,215 @@
|
|||
package me.ratsiel.json.model;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
import me.ratsiel.json.interfaces.IListable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The class Json object is used to store objects of type {@link JsonValue} in {@link #values}
|
||||
*/
|
||||
public class JsonObject extends JsonValue implements IListable<JsonValue> {
|
||||
|
||||
/**
|
||||
* The Values is a list which is used by the {@link IListable}
|
||||
*/
|
||||
protected final List<JsonValue> values = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Instantiates a new Json object.
|
||||
*/
|
||||
public JsonObject() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json object.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
*/
|
||||
public JsonObject(String key) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String space = createSpace();
|
||||
|
||||
stringBuilder.append(space);
|
||||
|
||||
if (getKey() != null && !getKey().isEmpty()) {
|
||||
stringBuilder.append("\"").append(getKey()).append("\"").append(" : ");
|
||||
}
|
||||
|
||||
stringBuilder.append("{");
|
||||
loop((integer, jsonValue) -> {
|
||||
jsonValue.setIntend(getIntend() + 2);
|
||||
stringBuilder.append("\n");
|
||||
if(!(integer == size() - 1)) {
|
||||
stringBuilder.append(jsonValue).append(",");
|
||||
} else {
|
||||
stringBuilder.append(jsonValue);
|
||||
}
|
||||
});
|
||||
stringBuilder.append("\n").append(space).append("}");
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get json value by key.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @return the json value is null or the Json value that is found in {@link #values}
|
||||
*/
|
||||
public JsonValue get(String key) {
|
||||
if(!has(key)) return null;
|
||||
|
||||
return values.stream().filter(jsonValue -> jsonValue.getKey().equalsIgnoreCase(key)).findFirst().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link T} by key and cast it to {@link Class<T>}
|
||||
*
|
||||
* @param <T> the type parameter is used to determine what type of object is needed
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @param clazz the clazz is used to cast the {@link T}
|
||||
* @return the {@link T} object
|
||||
*/
|
||||
public <T extends JsonValue> T get(String key, Class<T> clazz) {
|
||||
return clazz.cast(get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Has is used to find a {@link JsonValue} by its key in {@link #values}
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @return the boolean true or false
|
||||
*/
|
||||
public boolean has(String key) {
|
||||
return values.stream().anyMatch(jsonValue -> jsonValue.getKey() != null && jsonValue.getKey().equalsIgnoreCase(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets index.
|
||||
* Used to get the index of an key if it is found in {@link #values}
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @return the index by key
|
||||
*/
|
||||
public int getIndex(String key) {
|
||||
if(!has(key)) return -1;
|
||||
|
||||
for (int index = 0; index < values.size(); index++) {
|
||||
JsonValue jsonValue = values.get(index);
|
||||
if(jsonValue.getKey().equalsIgnoreCase(key)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to {@link #values} by its key.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @param jsonValue the json value is the {@link JsonValue} that is going to be added to {@link #values}
|
||||
*/
|
||||
public void add(String key, JsonValue jsonValue) {
|
||||
jsonValue.setKey(key);
|
||||
add(jsonValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(JsonValue value) {
|
||||
if(has(value.getKey())) {
|
||||
int index = getIndex(value.getKey());
|
||||
add(index, value);
|
||||
} else {
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, JsonValue value) {
|
||||
values.set(index, value);
|
||||
}
|
||||
|
||||
|
||||
public void addString(String key, String value) {
|
||||
JsonString jsonString = new JsonString(key, value);
|
||||
this.add(jsonString);
|
||||
}
|
||||
|
||||
public void addBoolean(String key, boolean value) {
|
||||
JsonBoolean jsonBoolean = new JsonBoolean(key, value);
|
||||
this.add(jsonBoolean);
|
||||
}
|
||||
|
||||
public void addByte(String key, byte value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addInteger(String key, int value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addShort(String key, short value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addDouble(String key, double value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addFloat(String key, float value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
public void addLong(String key, long value) {
|
||||
JsonNumber jsonNumber = new JsonNumber(key, String.valueOf(value));
|
||||
this.add(jsonNumber);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JsonValue get(int index, Class<JsonValue> clazz) {
|
||||
return clazz.cast(get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonValue get(int index) {
|
||||
return values.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop(Consumer<JsonValue> consumer) {
|
||||
for (JsonValue value : values) {
|
||||
consumer.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop(BiConsumer<Integer, JsonValue> consumer) {
|
||||
for (int index = 0; index < values.size(); index++) {
|
||||
JsonValue jsonValue = values.get(index);
|
||||
consumer.accept(index, jsonValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
73
src/main/java/me/ratsiel/json/model/JsonString.java
Normal file
73
src/main/java/me/ratsiel/json/model/JsonString.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
package me.ratsiel.json.model;
|
||||
|
||||
import me.ratsiel.json.abstracts.JsonValue;
|
||||
|
||||
/**
|
||||
* The class Json string is used to store a string.
|
||||
*/
|
||||
public class JsonString extends JsonValue {
|
||||
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Instantiates a new Json string.
|
||||
*/
|
||||
public JsonString() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json string.
|
||||
*
|
||||
* @param key the key is the identifier of {@link JsonValue}
|
||||
* @param value the value is the given string that is set to {@link #value}
|
||||
*/
|
||||
public JsonString(String key, String value) {
|
||||
super(key);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Json string.
|
||||
*
|
||||
* @param value the value is the given string that is set to {@link #value}
|
||||
*/
|
||||
public JsonString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String space = createSpace();
|
||||
|
||||
stringBuilder.append(space);
|
||||
if (getKey() != null && !getKey().isEmpty()) {
|
||||
stringBuilder.append("\"").append(getKey()).append("\"")
|
||||
.append(" : ").append("\"").append(getValue()).append("\"");
|
||||
} else {
|
||||
stringBuilder.append("\"").append(value).append("\"");
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets value.
|
||||
*
|
||||
* @return the value is the stored at {@link #value}
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value.
|
||||
*
|
||||
* @param value the value is set to {@link #value}
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import me.ratsiel.auth.abstracts.exception.AuthenticationException;
|
||||
import me.ratsiel.auth.model.mojang.MinecraftAuthenticator;
|
||||
import me.ratsiel.auth.model.mojang.MinecraftToken;
|
||||
import me.ratsiel.auth.model.mojang.profile.MinecraftProfile;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiTextField;
|
||||
|
@ -10,6 +14,7 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
|
||||
private GuiScreen parent;
|
||||
private GuiTextField username;
|
||||
private GuiTextField password;
|
||||
|
||||
private boolean dropDownOpen = false;
|
||||
private String[] dropDownOptions;
|
||||
|
@ -66,15 +71,16 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
this.dropDownOptions = EaglerProfile.concatArrays(EaglerProfile.skinNames.toArray(new String[0]), defaultOptions);
|
||||
}
|
||||
|
||||
private GuiButton button0, button1, button2, button3;
|
||||
private GuiButton button0, button1, button2, button3, button4;
|
||||
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
EaglerAdapter.enableRepeatEvents(true);
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
this.screenTitle = var1.translateKey("profile.title");
|
||||
this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20);
|
||||
this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 1, 138, 20);
|
||||
this.username.setFocused(true);
|
||||
this.password = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20);
|
||||
this.username.setText(EaglerProfile.username);
|
||||
selectedSlot = EaglerProfile.presetSkinId == -1 ? EaglerProfile.customSkinId : (EaglerProfile.presetSkinId + EaglerProfile.skinNames.size());
|
||||
//this.buttonList.add(new GuiButton(0, this.width / 2 - 100, 140, "eeeee"));
|
||||
|
@ -83,6 +89,8 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
this.buttonList.add(button2 = new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 110, 72, 20, var1.translateKey("profile.clearSkin")));
|
||||
|
||||
this.buttonList.add(button3 = new GuiButton(4, this.width / 2 - 21 + 71, this.height / 6 + 134, 72, 20, this.mc.gameSettings.useDefaultProtocol?"Switch to Eaglercraft":"Switch to Vanilla"));
|
||||
|
||||
this.buttonList.add(button4 = new GuiButton(5, this.width / 2 - 21, this.height / 6 + 134, 72, 20, this.mc.gameSettings.sessionId==null?"Microsoft Login":"Logout"));
|
||||
//this.buttonList.add(new GuiButton(200, this.width / 2, this.height / 6 + 72, 150, 20, var1.translateKey("gui.done")));
|
||||
}
|
||||
|
||||
|
@ -183,7 +191,7 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(!dropDownOpen) {
|
||||
if(par1GuiButton.id == 200) {
|
||||
EaglerProfile.username = this.username.getText().length() == 0 ? "null" : this.username.getText();
|
||||
if(mc.gameSettings.sessionId==null)EaglerProfile.username = this.username.getText().length() == 0 ? "null" : this.username.getText();
|
||||
EaglerProfile.presetSkinId = selectedSlot - EaglerProfile.skinNames.size();
|
||||
if(EaglerProfile.presetSkinId < 0) {
|
||||
EaglerProfile.presetSkinId = -1;
|
||||
|
@ -219,7 +227,23 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
}else if (par1GuiButton.id == 4) {
|
||||
//toggle version mode
|
||||
this.mc.gameSettings.useDefaultProtocol=!this.mc.gameSettings.useDefaultProtocol;
|
||||
button3.displayString=this.mc.gameSettings.useDefaultProtocol?"Switch to Eaglercraft":"Switch to Vanilla";
|
||||
this.button3.displayString=this.mc.gameSettings.useDefaultProtocol?"Switch to Eaglercraft":"Switch to Vanilla";
|
||||
}else if (par1GuiButton.id == 5) {
|
||||
//log in/out
|
||||
if(this.mc.gameSettings.sessionId==null){
|
||||
try {
|
||||
MinecraftAuthenticator minecraftAuthenticator = new MinecraftAuthenticator();
|
||||
MinecraftToken minecraftToken = minecraftAuthenticator.loginWithXbox(this.username.getText(), "");
|
||||
MinecraftProfile minecraftProfile = minecraftAuthenticator.checkOwnership(minecraftToken);
|
||||
this.button4.displayString="Logout";
|
||||
EaglerProfile.username=minecraftToken.getUsername();
|
||||
this.username.setText(EaglerProfile.username);
|
||||
this.password.setText("");
|
||||
mc.gameSettings.sessionId=minecraftToken.getAccessToken();
|
||||
}catch(AuthenticationException e){}
|
||||
}else{
|
||||
this.mc.gameSettings.sessionId=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,14 +294,18 @@ public class GuiScreenEditProfile extends GuiScreen {
|
|||
|
||||
public void onGuiClosed() {
|
||||
EaglerAdapter.enableRepeatEvents(false);
|
||||
if(mc.gameSettings.sessionId==null){
|
||||
EaglerProfile.username=EaglerProfile.username.replaceAll("@","");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//will be called for password typing as well lol, meh
|
||||
protected void keyTyped(char par1, int par2) {
|
||||
this.username.textboxKeyTyped(par1, par2);
|
||||
|
||||
|
||||
String text = username.getText();
|
||||
if(text.length() > 16) text = text.substring(0, 16);
|
||||
text = text.replaceAll("[^A-Za-z0-9\\-_]", "_");
|
||||
text = text.replaceAll("[^A-Za-z0-9\\-_@]", "_");
|
||||
this.username.setText(text);
|
||||
|
||||
if(par2 == 200 && selectedSlot > 0) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import net.minecraft.client.Minecraft;
|
|||
|
||||
public class GameSettings {
|
||||
public static boolean useDefaultProtocol = false;
|
||||
public static String sessionId = null;
|
||||
|
||||
|
||||
private static final String[] RENDER_DISTANCES = new String[] { "options.renderDistance.far", "options.renderDistance.normal", "options.renderDistance.short", "options.renderDistance.tiny" };
|
||||
|
|
Loading…
Reference in New Issue
Block a user