En .yml:
application.yml
sirec:
kill-list-enabled: ${KILL_LIST_ENABLED:false}
O en .properties:
application.properties
sirec.kill-list-enabled: ${KILL_LIST_ENABLED:false}
Y en Java:
ApiTareasService.java
@Value("#{new Boolean('${sirec.kill-list-enabled:false}')}")
private Boolean killListEnabled;
if (killListEnabled) {
...
}
lunes, 29 de noviembre de 2021
Java: utilizar el valor de una property en una clase.
Java: sumar días o meses a una fecha en formato String
public static final String FECHA_FORMATO_ENTRADA = "yyyy-MM-dd HH:mm:ss.S";
public static final String FECHA_FORMATO_SALIDA = "dd/MM/yyyy";
SimpleDateFormat formatIn = new SimpleDateFormat(Constants.FECHA_FORMATO_ENTRADA);
SimpleDateFormat formatOut = new SimpleDateFormat(Constants.FECHA_FORMATO_SALIDA);
String tmpFecha = null;
try {
Date dateSel = formatIn.parse(valoracionesBienInner.getFecha());
Calendar calendar = Calendar.getInstance();
calendar.setTime(dateSel);
calendar.add(Calendar.MONTH, Integer.valueOf(valoracionesBienInner.getPeriodoValidez()));
Date salida = calendar.getTime();
tmpFecha = formatOut.format(salida);
} catch (ParseException e) {
throw new SirecApplicationException(0, "Error parseo fecha validez en valoraciones", e);
}
aElementoListaValoraciones.setFechaValidez(getNullHandlingValue(tmpFecha));
public static String getNullHandlingValue(String valor) {
return valor == null ? "" : valor;
}
miércoles, 20 de octubre de 2021
Java RestCall (TODO)
// Requires:
//<!-- https://mvnrepository.com/artifact/net.minidev/json-smart -->
//<dependency>
// <groupId>net.minidev</groupId>
// <artifactId>json-smart</artifactId>
// <version>2.4.7</version>
//</dependency>
package com.thymewizards.util;
import java.util.Map;
import net.minidev.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
public class RestCall {
private static final Logger logger = LoggerFactory.getLogger(RestCall.class);
private RestTemplate restTemplate = new RestTemplate();
public ResponseEntity<Object> executePOST(String url, HttpHeaders header, Map<String, String> urlParams, MultiValueMap<String, String> queryParams, Object obj) throws Exception {
ResponseEntity<Object> resp = null;
UriComponents builder = null;
try {
if (obj != null) {
logger.info(String.format("{Body} : %s", obj.toString()));
}
builder = UriComponentsBuilder.fromHttpUrl(url).buildAndExpand(urlParams);
if (queryParams != null) {
builder = UriComponentsBuilder.fromUriString(url).queryParams(queryParams).buildAndExpand(urlParams);
}
HttpEntity<Object> httpEntity = new HttpEntity(obj, header);
logger.info(String.format("{Header} : %s", httpEntity.getHeaders()));
logger.info(String.format("Accediendo a la URL %s via POST", builder.toUriString()));
resp = this.restTemplate.postForEntity(builder.toUriString(), httpEntity, Object.class, new Object[1]);
if (resp != null) {
logger.info(String.format("{Response} : %s", resp));
}
logger.info("OK.!");
} catch (HttpStatusCodeException var9) {
logger.error("KO.! Error!!", var9);
throw var9;
} catch (Exception var10) {
logger.error(String.format("Accediendo a la URL {%s} via POST KO.! Error!!", url), var10);
throw new Exception(var10);
return resp;
}
}
public ResponseEntity<Object> executePUT(String url, HttpHeaders header, Map<String, String> urlParams, MultiValueMap<String, String> queryParams, Object obj) throws Exception {
ResponseEntity<Object> resp = null;
UriComponents builder = null;
try {
if (obj != null) {
logger.info(String.format("{Body} : %s", obj.toString()));
}
builder = UriComponentsBuilder.fromHttpUrl(url).buildAndExpand(urlParams);
if (queryParams != null) {
builder = UriComponentsBuilder.fromUriString(url).queryParams(queryParams).buildAndExpand(urlParams);
}
HttpEntity<Object> httpEntity = new HttpEntity(obj, header);
logger.info(String.format("{Header} : %s", httpEntity.getHeaders()));
logger.info(String.format("Accediendo a la URL %s via PUT", builder.toUriString()));
resp = this.restTemplate.exchange(builder.toUriString(), HttpMethod.PUT, httpEntity, Object.class, new Object[0]);
if (resp != null) {
logger.info(String.format("{Response} : %s", resp));
}
logger.info("OK.!");
} catch (HttpStatusCodeException var9) {
logger.error("KO.! Error!!", var9);
throw var9;
} catch (Exception var10) {
logger.error(String.format("Accediendo a la URL {%s} via PUT KO.! Error!!", builder), var10);
throw new Exception(var10);
return resp;
}
}
public ResponseEntity<Object> executeDELETE(String url, HttpHeaders header, Map<String, String> urlParams, MultiValueMap<String, String> queryParams) throws Exception {
ResponseEntity<Object> resp = null;
UriComponents builder = null;
try {
builder = UriComponentsBuilder.fromHttpUrl(url).buildAndExpand(urlParams);
if (queryParams != null) {
builder = UriComponentsBuilder.fromUriString(url).queryParams(queryParams).buildAndExpand(urlParams);
}
HttpEntity<Object> httpEntity = new HttpEntity(header);
logger.info(String.format("{Header} : %s", httpEntity.getHeaders()));
logger.info(String.format("Accediendo a la URL %s via DELETE", builder.toUriString()));
resp = this.restTemplate.exchange(builder.toUriString(), HttpMethod.DELETE, httpEntity, Object.class, new Object[0]);
logger.info(String.format("{Response} : %s", resp));
logger.info("OK.!");
} catch (HttpStatusCodeException var8) {
logger.error("KO.! Error!!", var8);
throw var8;
} catch (Exception var9) {
logger.error(String.format("Accediendo a la URL {%s} via DELETE KO.! Error!!", url), var9);
throw new Exception(var9);
return resp;
}
}
public ResponseEntity<Object> executeGET(String url, HttpHeaders header, Map<String, String> urlParams, MultiValueMap<String, String> queryParams, Object obj) throws Exception {
ResponseEntity<Object> resp = null;
UriComponents builder = null;
try {
if (obj != null) {
logger.info(String.format("{Body} : %s", obj.toString()));
}
builder = UriComponentsBuilder.fromHttpUrl(url).buildAndExpand(urlParams);
if (queryParams != null) {
builder = UriComponentsBuilder.fromUriString(url).queryParams(queryParams).buildAndExpand(urlParams);
}
HttpEntity<Object> httpEntity = new HttpEntity(obj, header);
logger.info(String.format("{Header} : %s", header));
logger.info(String.format("Accediendo a la URL %s via GET", builder.toUriString()));
resp = this.restTemplate.exchange(builder.toUriString(), HttpMethod.GET, httpEntity, Object.class, new Object[0]);
if (resp != null) {
logger.info(String.format("{Response} : %s", resp));
}
logger.info("OK.!");
} catch (HttpStatusCodeException var9) {
logger.error("KO.! Error!!", var9);
throw var9;
} catch (Exception var10) {
logger.error(String.format("Accediendo a la URL {%s} via GET KO.! Error!!", url), var10);
throw new Exception(var10);
return resp;
}
}
public Object rest2Object(ResponseEntity<Object> resp, Object obj) throws Exception {
if (obj == null) {
throw new Exception(String.format("Error el objecto <%s> es nulo", obj));
} else {
try {
if (!resp.getStatusCode().equals(HttpStatus.OK) && !resp.getStatusCode().equals(HttpStatus.CREATED)) {
} else {
JSONObject jsonBody = new JSONObject((Map) resp.getBody());
return ObjectMapperFactory.defaultOne().readValue(jsonBody.toJSONString(), obj.getClass());
}
} catch (Exception var4) {
logger.error(String.format("Error al convertir <%s>", resp, obj.getClass().getSimpleName()), var4);
throw new Exception(var4);
return obj;
}
}
}
}
@Slf4j
@RequiredArgsConstructor
public class ApiCuotasOnlineService extends ApiDelegateBaseHandler implements IApiCuotasOnlineService {
private final ICuentaService cuentaService;
private final HttpServletRequest request;
@Value("${sirec.restcall.host:http://www.xyzxyz.es/}")
private String host;
@Override
@SuppressWarnings("checkstyle:ParameterNumber")
public CuotasContrato obtenerCuotasProducto(final String agrupacionAdn,
final String numeroContrato, final String situacion, final String fechaDesde, final String fechaHasta,
final String date, final String number, final String currency, final String balancePosition) {
CuotasContrato cuotasContrato = new CuotasContrato();
Tabla2Respuesta respuesta = new Tabla2Respuesta();
List<TablaRespuestaColumnas> columnas = obtenerColumnasCuotasOnline();
respuesta.setColumnas(columnas);
if (columnas != null && !columnas.isEmpty()) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
queryParams.add("agrupacionAdn", agrupacionAdn);
queryParams.add("numeroContrato", numeroContrato);
queryParams.add("situacion", situacion);
queryParams.add("fechaDesde", fechaDesde);
queryParams.add("fechaHasta", fechaHasta);
queryParams.add("date", date);
queryParams.add("number", number);
queryParams.add("currency", currency);
queryParams.add("balancePosition", balancePosition);
List<Map<String, String>> datos = obtenerDatosCuotasProducto(queryParams, columnas);
respuesta.setDatos(datos);
}
cuotasContrato.setRespuesta(respuesta);
return cuotasContrato;
}
private List<Map<String, String>> obtenerDatosCuotasProducto(final MultiValueMap<String, String> queryParams,
final List<TablaRespuestaColumnas> columnas) {
RestCall restCall = new RestCall();
List<Map<String, String>> datos = new ArrayList<>();
ListaConsultaOnline detalle = new ListaConsultaOnline();
List<Map<String, String>> datosFiltrados = new ArrayList<>();
HttpHeaders headers = createDefaultHttpHeaders();
ResponseEntity<Object> resp;
try {
resp = (ResponseEntity<Object>) restCall.executeGET(
host + "api/core/v1/consultasOnline/cuotas", headers, new HashMap<String, String>(),
queryParams, null);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new SirecApplicationException(0, e.getMessage(), e);
}
try {
detalle = (ListaConsultaOnline) restCall.rest2Object(resp, (Object) detalle);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
datos = detalle.getRespuesta().getDatos();
// Se filtran los datos que coinciden con las columnas
for (Map<String, String> dato : datos) {
Map<String, String> map = new HashMap();
for (TablaRespuestaColumnas columna : columnas) {
map.put(columna.getId(), dato.get(columna.getId()));
}
datosFiltrados.add(map);
}
return datosFiltrados;
}
private List<TablaRespuestaColumnas> obtenerColumnasCuotasOnline() {
log.info("ApiCuotasOnlineService.obtenerColumnasCuotasOnline");
CuentaCamposDTO cuentaCamposDTO = new CuentaCamposDTO();
cuentaCamposDTO = cuentaService.obtenerCamposDetalleCuotasOnlinePrestamosImpagados();
return obtenerColumnasPreparadasCuotasOnline(cuentaCamposDTO);
}
private List<TablaRespuestaColumnas> obtenerColumnasPreparadasCuotasOnline(final CuentaCamposDTO cuentaCamposDTO) {
// Campos configurables
List<TablaRespuestaColumnas> columnas = new ArrayList<TablaRespuestaColumnas>();
// Columnas
if (cuentaCamposDTO != null && cuentaCamposDTO.getCampos() != null) {
List<CampoConfiguracionInner> listCamposMostrar = new ArrayList<>();
for (CampoConfiguracionInner campo : cuentaCamposDTO.getCampos()) {
if (campo.getOrden() != null && campo.getOrden() > 0) {
listCamposMostrar.add(campo);
}
}
listCamposMostrar.sort(Comparator.comparing(CampoConfiguracionInner::getOrden));
// Columnas dinamicas
columnas = listCamposMostrar.stream().map(campos -> new TablaRespuestaColumnas()
.id(campos.getNombreTecnicoCampo()).label(campos.getCampo()).tipo(campos.getTipoDato()))
.collect(Collectors.toList());
} else {
columnas.add(new TablaRespuestaColumnas());
}
return columnas;
}
private HttpHeaders createDefaultHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
Enumeration<?> names = request.getHeaderNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
Enumeration<?> values = request.getHeaders(name);
while (values.hasMoreElements()) {
headers.add(name, (String) values.nextElement());
}
}
return headers;
}
}
@Slf4j
@RequiredArgsConstructor
public class ApiPaygoldService extends ApiDelegateBaseHandler implements IApiPaygoldService {
private final HttpServletRequest request;
@Value("${sirec.restcall.host:http://www.xyzxyz.es/}")
private String host;
@Override
public DetalleConsultaOnline paygold(final PaygoldEntrada paygoldEntrada) {
DetalleConsultaOnline detalleConsultaOnline = new DetalleConsultaOnline();
DetalleConsultaOnlineRespuesta respuesta = new DetalleConsultaOnlineRespuesta();
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
Map<String, String> datos = obtenerDatosRespuestaPaygold(queryParams, paygoldEntrada);
respuesta.setDatos(datos);
detalleConsultaOnline.setRespuesta(respuesta);
return detalleConsultaOnline;
}
private Map<String, String> obtenerDatosRespuestaPaygold(final MultiValueMap<String, String> queryParams,
final PaygoldEntrada paygoldEntrada) {
RestCall restCall = new RestCall();
DetalleConsultaOnline detalle = new DetalleConsultaOnline();
Map<String, String> datos = new HashMap<String, String>();
HttpHeaders headers = createDefaultHttpHeaders();
ResponseEntity<Object> resp;
try {
resp = (ResponseEntity<Object>) restCall.executePOST(
host + "api/core/v1/consultasOnline/paygold", headers, new HashMap<String, String>(),
queryParams, paygoldEntrada);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new SirecApplicationException(0, e.getMessage(), e);
}
try {
detalle = (DetalleConsultaOnline) restCall.rest2Object(resp, (Object) detalle);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
datos = detalle.getRespuesta().getDatos();
return datos;
}
private HttpHeaders createDefaultHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
Enumeration<?> names = request.getHeaderNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
Enumeration<?> values = request.getHeaders(name);
while (values.hasMoreElements()) {
headers.add(name, (String) values.nextElement());
}
}
return headers;
}
}
Convertir importes de String a Bigdecimal
/**
* Convierte un importe de String con . para miles y , para decimales a BigDecimal
* @param valor Valor a formatear
* @return
*/
public static BigDecimal stringToBigDecimal(final String valor) {
BigDecimal valorDecimal = null;
try {
valorDecimal = new BigDecimal(valor);
} catch (NumberFormatException e) {
String valorReplace = valor.replace(".", "").replace(",", ".");
try {
valorDecimal = new BigDecimal(valorReplace);
} catch (NumberFormatException e2) {
log.error(e2.getMessage());
}
}
return valorDecimal;
}
lunes, 4 de octubre de 2021
Java Formatea una fecha String de yyyy-MM-dd a dd/MM/yyyy
/**
* Formatea una fecha String de yyyy-MM-dd a dd/MM/yyyy
* @param fechaOrigen
* @return
*/
public static String formateoFechaString(final String fechaOrigen) {
String fechaDestino = "";
if (null != fechaOrigen && !fechaOrigen.isEmpty()) {
DateTimeFormatter formatoOrigen = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter formatoDestino = DateTimeFormatter.ofPattern("dd/MM/yyyy");
fechaDestino = LocalDate.parse(fechaOrigen, formatoOrigen).format(formatoDestino);
}
return fechaDestino;
}
Java: Cambiar formato de importe String a coma para decimales y puntos para miles
private static final String PATTERN = "#,##0.00";
/**
* Formatea un importe a String en formato numerico
* @param valor Valor a formatear
* @param entrada Indica true para entrada (hacia tx) o false para salida (hacia
* front)
* @return
*/
public static String formatImporte(final String valor, final boolean entrada) {
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getNumberInstance(Locale.GERMAN);
decimalFormat.applyPattern(PATTERN);
if (valor != null && !"".equals(valor.trim())) {
double conValor = 0;
try {
conValor = Double.parseDouble(valor);
} catch (NumberFormatException e) {
String valorReplace = valor.replace(".", "").replace(",", ".");
conValor = Double.parseDouble(valorReplace);
}
if (entrada) {
return Double.toString(conValor);
} else {
return decimalFormat.format(conValor);
}
}
return valor;
}
Java: Sumar, redondear BigDecimal, y convertir a String
map.put("balance", refinancingLoanItem.getBalances().getTotalUnpaidAmount().getAmount().add(refinancingLoanItem.getBalances().getOutstandingCapital().getAmount()).setScale(2, BigDecimal.ROUND_CEILING).toPlainString());
martes, 18 de mayo de 2021
Ordenar una lista de objetos en Java
lstPersonasCuentaDo.sort(Comparator.comparing(Persona::getNombreCompleto, Comparator.nullsLast(Comparator.naturalOrder())));
jueves, 18 de marzo de 2021
Identificarse en GitHub con token de acceso en lugar de contraseña (Eclipse y STS)
If you're using Two Factor Authentication on GitHub, the "not authorized" error can be returned even if you are using the correct username and password. This can be resolved by generating a personal access token.
After generating the secure access token, we'll use this instead of a password. Make sure not to leave the page before you're done, because once you leave the page, you'll never see it again (thankfully it can be regenerated, but anything using the previously generated token will cease to authenticate).
This assumes that you've successfully installed EGit and that you've successfully cloned a repository.
- Go to your GitHub.com settings, and in the left hand pane click
Personal access tokens. - Click
Generate new token. Select the scopes that you'd like this token to be able to use, and generate it. - Copy the token. It should look something like this:
9731f5cf519e9abb53e6ba9f5134075438944888(don't worry, this is invalid). - Back in Eclipse (Juno, since that's OP's version), click
Window > Show View > Other.... UnderGit, selectGit Repositories. - A new pane appears, from which you can open
(repository name) > Remotes > origin. - Right click on a node and choose
Change Credentials.... Enter your username forUser, and your secure access token for thePassword.
Tabla de conversión de símbolos UTF-8 a ISO-8859-1 (ANSI)
| Latin1 | UTF-1 | UTF-8 | UTF-7,5 | UTF-7 | JAVA | HTML |
|  | ¢à | +AKA- | \u00a0 |   | ||
| ¡ | ¡ | ¡ | ¢á | +AKE- | \u00a1 | ¡ |
| ¢ | ¢ | ¢ | ¢â | +AKI- | \u00a2 | ¢ |
| £ | £ | £ | ¢ã | +AKM- | \u00a3 | £ |
| ¤ | ¤ | ¤ | ¢ä | +AKQ- | \u00a4 | ¤ |
| ¥ | ¥ | Â¥ | ¢å | +AKU- | \u00a5 | ¥ |
| ¦ | ¦ | ¦ | ¢æ | +AKY- | \u00a6 | ¦ |
| § | § | § | ¢ç | +AKc- | \u00a7 | § |
| ¨ | ¨ | ¨ | ¢è | +AKg- | \u00a8 | ¨ |
| © | © | © | ¢é | +AKk- | \u00a9 | © |
| ª | ª | ª | ¢ê | +AKo- | \u00aa | ª |
| « | « | « | ¢ë | +AKs- | \u00ab | « |
|  | ¢ì | +AKw- | \u00ac | ¬ | ||
| | |  | ¢í | +AK0- | \u00ad | ­ |
| ® | ® | ® | ¢î | +AK4- | \u00ae | ® |
| ¯ | ¯ | ¯ | ¢ï | +AK8- | \u00af | ¯ |
| ° | ° | ° | ¢ð | +ALA- | \u00b0 | ° |
| ± | ± | ± | ¢ñ | +ALE- | \u00b1 | ± |
| ² | ² | ² | ¢ò | +ALI- | \u00b2 | ² |
| ³ | ³ | ³ | ¢ó | +ALM- | \u00b3 | ³ |
| ´ | ´ | ´ | ¢ô | +ALQ- | \u00b4 | ´ |
| µ | µ | µ | ¢õ | +ALU- | \u00b5 | µ |
| Â | ¢ö | +ALY- | \u00b6 | ¶ | ||
| · | · | · | ¢÷ | +ALc- | \u00b7 | · |
| ¸ | ¸ | ¸ | ¢ø | +ALg- | \u00b8 | ¸ |
| ¹ | ¹ | ¹ | ¢ù | +ALk- | \u00b9 | ¹ |
| º | º | º | ¢ú | +ALo- | \u00ba | º |
| » | » | » | ¢û | +ALs- | \u00bb | » |
| ¼ | ¼ | ¼ | ¢ü | +ALw- | \u00bc | ¼ |
| ½ | ½ | ½ | ¢ý | +AL0- | \u00bd | ½ |
| ¾ | ¾ | ¾ | ¢þ | +AL4- | \u00be | ¾ |
| ¿ | ¿ | ¿ | ¢ÿ | +AL8- | \u00bf | ¿ |
| À | À | À | £À | +AMA- | \u00c0 | À |
| Á | Á | à | £Á | +AME- | \u00c1 | Á |
|  |  |  | £Â | +AMI- | \u00c2 |  |
| à | à | à | £Ã | +AMM- | \u00c3 | à |
| Ä | Ä | Ä | £Ä | +AMQ- | \u00c4 | Ä |
| Å | Å | Ã… | £Å | +AMU- | \u00c5 | Å |
| Æ | Æ | Æ | £Æ | +AMY- | \u00c6 | Æ |
| Ç | Ç | Ç | £Ç | +AMc- | \u00c7 | Ç |
| È | È | È | £È | +AMg- | \u00c8 | È |
| É | É | É | £É | +AMk- | \u00c9 | É |
| Ê | Ê | Ê | £Ê | +AMo- | \u00ca | Ê |
| Ë | Ë | Ë | £Ë | +AMs- | \u00cb | Ë |
| Ì | Ì | ÃŒ | £Ì | +AMw- | \u00cc | Ì |
| Í | Í | à | £Í | +AM0- | \u00cd | Í |
| Î | Î | ÃŽ | £Î | +AM4- | \u00ce | Î |
| Ï | Ï | à | £Ï | +AM8- | \u00cf | Ï |
| Ð | Ð | à | £Ð | +ANA- | \u00d0 | Ð |
| Ñ | Ñ | Ñ | £Ñ | +ANE- | \u00d1 | Ñ |
| Ò | Ò | Ã’ | £Ò | +ANI- | \u00d2 | Ò |
| Ó | Ó | Ó | £Ó | +ANM- | \u00d3 | Ó |
| Ô | Ô | Ô | £Ô | +ANQ- | \u00d4 | Ô |
| Õ | Õ | Õ | £Õ | +ANU- | \u00d5 | Õ |
| Ö | Ö | Ö | £Ö | +ANY- | \u00d6 | Ö |
| × | × | × | £× | +ANc- | \u00d7 | × |
| Ø | Ø | Ø | £Ø | +ANg- | \u00d8 | Ø |
| Ù | Ù | Ù | £Ù | +ANk- | \u00d9 | Ù |
| Ú | Ú | Ú | £Ú | +ANo- | \u00da | Ú |
| Û | Û | Û | £Û | +ANs- | \u00db | Û |
| Ü | Ü | Ü | £Ü | +ANw- | \u00dc | Ü |
| Ý | Ý | à | £Ý | +AN0- | \u00dd | Ý |
| Þ | Þ | Þ | £Þ | +AN4- | \u00de | Þ |
| ß | ß | ß | £ß | +AN8- | \u00df | ß |
| à | à | à | £à | +AOA- | \u00e0 | à |
| á | á | á | £á | +AOE- | \u00e1 | á |
| â | â | â | £â | +AOI- | \u00e2 | â |
| ã | ã | ã | £ã | +AOM- | \u00e3 | ã |
| ä | ä | ä | £ä | +AOQ- | \u00e4 | ä |
| å | å | Ã¥ | £å | +AOU- | \u00e5 | å |
| æ | æ | æ | £æ | +AOY- | \u00e6 | æ |
| ç | ç | ç | £ç | +AOc- | \u00e7 | ç |
| è | è | è | £è | +AOg- | \u00e8 | è |
| é | é | é | £é | +AOk- | \u00e9 | é |
| ê | ê | ê | £ê | +AOo- | \u00ea | ê |
| ë | ë | ë | £ë | +AOs- | \u00eb | ë |
| ì | ì | à | £ì | +AOw- | \u00ec | ì |
| í | í | à | £í | +AO0- | \u00ed | í |
| î | î | î | £î | +AO4- | \u00ee | î |
| ï | ï | ï | £ï | +AO8- | \u00ef | ï |
| ð | ð | ð | £ð | +APA- | \u00f0 | ð |
| ñ | ñ | ñ | £ñ | +APE- | \u00f1 | ñ |
| ò | ò | ò | £ò | +API- | \u00f2 | ò |
| ó | ó | ó | £ó | +APM- | \u00f3 | ó |
| ô | ô | ô | £ô | +APQ- | \u00f4 | ô |
| õ | õ | õ | £õ | +APU- | \u00f5 | õ |
| ö | ö | Ã | £ö | +APY- | \u00f6 | ö |
| ÷ | ÷ | ÷ | £÷ | +APc- | \u00f7 | ÷ |
| ø | ø | ø | £ø | +APg- | \u00f8 | ø |
| ù | ù | ù | £ù | +APk- | \u00f9 | ù |
| ú | ú | ú | £ú | +APo- | \u00fa | ú |
| û | û | û | £û | +APs- | \u00fb | û |
| ü | ü | ü | £ü | +APw- | \u00fc | ü |
| ý | ý | ý | £ý | +AP0- | \u00fd | ý |
| þ | þ | þ | £þ | +AP4- | \u00fe | þ |
| ÿ | ÿ | ÿ | £ÿ | +AP8- | \u00ff | ÿ |
jueves, 4 de marzo de 2021
Java Reflection
1. Overview
In this article, we will be exploring Java reflection, which allows us to inspect or/and modify runtime attributes of classes, interfaces, fields, and methods. This particularly comes in handy when we don't know their names at compile time.
Additionally, we can instantiate new objects, invoke methods, and get or set field values using reflection.
2. Project Setup
To use Java reflection, we do not need to include any special jars, any special configuration, or Maven dependencies. The JDK ships with a group of classes that are bundled in the java.lang.reflect package specifically for this purpose.
So all we need to do is to make the following import into our code:
import java.lang.reflect.*;
and we are good to go.
To get access to the class, method, and field information of an instance we call the getClass method which returns the runtime class representation of the object. The returned class object provides methods for accessing information about a class.
3. Simple Example
To get our feet wet, we are going to take a look at a very basic example that inspects the fields of a simple Java object at runtime.
Let's create a simple Person class with only name and age fields and no methods at all. Here is the Person class:
public class Person {
private String name;
private int age;
}
We will now use Java reflection to discover the names of all fields of this class. To appreciate the power of reflection, we will construct a Person object and use Object as the reference type:
@Test
public void givenObject_whenGetsFieldNamesAtRuntime_thenCorrect() {
Object person = new Person();
Field[] fields = person.getClass().getDeclaredFields();
List<String> actualFieldNames = getFieldNames(fields);
assertTrue(Arrays.asList("name", "age")
.containsAll(actualFieldNames));
}This test shows us that we are able to get an array of Field objects from our person object, even if the reference to the object is a parent type of that object.
In the above example, we were only interested in the names of those fields, but there is much more that can be done and we will see further examples of this in the subsequent sections.
Notice how we use a helper method to extract the actual field names, it's a very basic code:
private static List<String> getFieldNames(Field[] fields) {
List<String> fieldNames = new ArrayList<>();
for (Field field : fields)
fieldNames.add(field.getName());
return fieldNames;
}
4. Java Reflection Use Cases
Before we proceed to the different features of Java reflection, we will discuss some of the common uses we may find for it. Java reflection is extremely powerful and can come in very handy in a number of ways.
For instance, in many cases, we have a naming convention for database tables. We may choose to add consistency by pre-fixing our table names with tbl_, such that a table with student data is called tbl_student_data.
In such cases, we may name the Java object holding student data as Student or StudentData. Then using the CRUD paradigm, we have one entry point for each operation such that Create operations only receive an Object parameter.
We then use reflection to retrieve the object name and field names. At this point, we can map this data to a DB table and assign the object field values to the appropriate DB field names.
5. Inspecting Java Classes
In this section, we will explore the most fundamental component in the Java reflection API. Java class objects, as we mentioned earlier, give us access to the internal details of any object.
We are going to examine internal details such as an object's class name, modifiers, fields, methods, implemented interfaces, etc.
5.1. Getting Ready
To get a firm grip on the reflection API, as applied to Java classes and have examples with variety, we will create an abstract Animal class which implements the Eating interface. This interface defines the eating behavior of any concrete Animal object we create.
So firstly, here is the Eating interface:
public interface Eating {
String eats();
}
and then the concrete Animal implementation of the Eating interface:
public abstract class Animal implements Eating {
public static String CATEGORY = "domestic";
private String name;
protected abstract String getSound();
// constructor, standard getters and setters omitted
}
Let's also create another interface called Locomotion which describes how an animal moves:
public interface Locomotion {
String getLocomotion();
}
We will now create a concrete class called Goat which extends Animal and implements Locomotion. Since the superclass implements Eating, Goat will have to implement that interface's methods as well:
public class Goat extends Animal implements Locomotion {
@Override
protected String getSound() {
return "bleat";
}
@Override
public String getLocomotion() {
return "walks";
}
@Override
public String eats() {
return "grass";
}
// constructor omitted
}
From this point onward, we will use Java reflection to inspect aspects of Java objects that appear in the classes and interfaces above.
5.2. Class Names
Let's start by getting the name of an object from the Class:
@Test
public void givenObject_whenGetsClassName_thenCorrect() {
Object goat = new Goat("goat");
Class<?> clazz = goat.getClass();
assertEquals("Goat", clazz.getSimpleName());
assertEquals("com.baeldung.reflection.Goat", clazz.getName());
assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName());
}
Note that the getSimpleName method of Class returns the basic name of the object as it would appear in its declaration. Then the other two methods return the fully qualified class name including the package declaration.
Let's also see how we can create an object of the Goat class if we only know its fully qualified class name:
@Test
public void givenClassName_whenCreatesObject_thenCorrect(){
Class<?> clazz = Class.forName("com.baeldung.reflection.Goat");
assertEquals("Goat", clazz.getSimpleName());
assertEquals("com.baeldung.reflection.Goat", clazz.getName());
assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName());
}
Notice that the name we pass to the static forName method should include the package information. Otherwise, we will get a ClassNotFoundException.
5.3. Class Modifiers
We can determine the modifiers used in a class by calling the getModifiers method which returns an Integer. Each modifier is a flag bit which is either set or cleared.
The java.lang.reflect.Modifier class offers static methods that analyze the returned Integer for the presence or absence of a specific modifier.
Let's confirm the modifiers of some of the classes we defined above:
@Test
public void givenClass_whenRecognisesModifiers_thenCorrect() {
Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");
Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");
int goatMods = goatClass.getModifiers();
int animalMods = animalClass.getModifiers();
assertTrue(Modifier.isPublic(goatMods));
assertTrue(Modifier.isAbstract(animalMods));
assertTrue(Modifier.isPublic(animalMods));
}
We are able to inspect modifiers of any class located in a library jar that we are importing into our project.
In most cases, we may need to use the forName approach rather than the full-blown instantiation since that would be an expensive process in the case of memory heavy classes.
5.4. Package Information
By using Java reflection we are also able to get information about the package of any class or object. This data is bundled inside the Package class which is returned by a call to getPackage method on the class object.
Let's run a test to retrieve the package name:
@Test
public void givenClass_whenGetsPackageInfo_thenCorrect() {
Goat goat = new Goat("goat");
Class<?> goatClass = goat.getClass();
Package pkg = goatClass.getPackage();
assertEquals("com.baeldung.reflection", pkg.getName());
} 5.5. Super Class
We are also able to obtain the superclass of any Java class by using Java reflection.
In many cases, especially while using library classes or Java's builtin classes, we may not know beforehand the superclass of an object we are using, this subsection will show how to obtain this information.
So let's go ahead and determine the superclass of Goat. Additionally, we also show that java.lang.String class is a subclass of java.lang.Object class:
@Test
public void givenClass_whenGetsSuperClass_thenCorrect() {
Goat goat = new Goat("goat");
String str = "any string";
Class<?> goatClass = goat.getClass();
Class<?> goatSuperClass = goatClass.getSuperclass();
assertEquals("Animal", goatSuperClass.getSimpleName());
assertEquals("Object", str.getClass().getSuperclass().getSimpleName());
}5.6. Implemented Interfaces
Using Java reflection, we are also able to get the list of interfaces implemented by a given class.
Let's retrieve the class types of the interfaces implemented by the Goat class and the Animal abstract class:
@Test
public void givenClass_whenGetsImplementedInterfaces_thenCorrect(){
Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");
Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");
Class<?>[] goatInterfaces = goatClass.getInterfaces();
Class<?>[] animalInterfaces = animalClass.getInterfaces();
assertEquals(1, goatInterfaces.length);
assertEquals(1, animalInterfaces.length);
assertEquals("Locomotion", goatInterfaces[0].getSimpleName());
assertEquals("Eating", animalInterfaces[0].getSimpleName());
}
Notice from the assertions that each class implements only a single interface. Inspecting the names of these interfaces, we find that Goat implements Locomotion and Animal implements Eating, just as it appears in our code.
You may have observed that Goat is a subclass of the abstract class Animal and implements the interface method eats(), then, Goat also implements the Eating interface.
It is therefore worth noting that only those interfaces that a class explicitly declares as implemented with the implements keyword appear in the returned array.
So even if a class implements interface methods because its superclass implements that interface, but the subclass does not directly declare that interface with the implements keyword, then that interface will not appear in the array of interfaces.
5.7. Constructors, Methods, and Fields
With Java reflection, we are able to inspect the constructors of any object's class as well as methods and fields.
We will, later on, be able to see deeper inspections on each of these components of a class but for now, it suffices to just get their names and compare them with what we expect.
Let's see how to get the constructor of the Goat class:
@Test
public void givenClass_whenGetsConstructor_thenCorrect(){
Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");
Constructor<?>[] constructors = goatClass.getConstructors();
assertEquals(1, constructors.length);
assertEquals("com.baeldung.reflection.Goat", constructors[0].getName());
}
We can also inspect the fields of the Animal class like so:
@Test
public void givenClass_whenGetsFields_thenCorrect(){
Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");
Field[] fields = animalClass.getDeclaredFields();
List<String> actualFields = getFieldNames(fields);
assertEquals(2, actualFields.size());
assertTrue(actualFields.containsAll(Arrays.asList("name", "CATEGORY")));
}
Just like we can inspect the methods of the Animal class:
@Test
public void givenClass_whenGetsMethods_thenCorrect(){
Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");
Method[] methods = animalClass.getDeclaredMethods();
List<String> actualMethods = getMethodNames(methods);
assertEquals(4, actualMethods.size());
assertTrue(actualMethods.containsAll(Arrays.asList("getName",
"setName", "getSound")));
}
Just like getFieldNames, we have added a helper method to retrieve method names from an array of Method objects:
private static List<String> getMethodNames(Method[] methods) {
List<String> methodNames = new ArrayList<>();
for (Method method : methods)
methodNames.add(method.getName());
return methodNames;
}6. Inspecting Constructors
With Java reflection, we can inspect constructors of any class and even create class objects at runtime. This is made possible by the java.lang.reflect.Constructor class.
Earlier on, we only looked at how to get the array of Constructor objects, from which we were able to get the names of the constructors.
In this section, we will focus on how to retrieve specific constructors. In Java, as we know, no two constructors of a class share exactly the same method signature. So we will use this uniqueness to get one constructor from many.
To appreciate the features of this class, we will create a Bird subclass of Animal with three constructors. We will not implement Locomotion so that we can specify that behavior using a constructor argument, to add still more variety:
public class Bird extends Animal {
private boolean walks;
public Bird() {
super("bird");
}
public Bird(String name, boolean walks) {
super(name);
setWalks(walks);
}
public Bird(String name) {
super(name);
}
public boolean walks() {
return walks;
}
// standard setters and overridden methods
}
Let's confirm by using reflection that this class has three constructors:
@Test
public void givenClass_whenGetsAllConstructors_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Constructor<?>[] constructors = birdClass.getConstructors();
assertEquals(3, constructors.length);
}
Next, we will retrieve each constructor for the Bird class by passing the constructor's parameter class types in declared order:
@Test
public void givenClass_whenGetsEachConstructorByParamTypes_thenCorrect(){
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Constructor<?> cons1 = birdClass.getConstructor();
Constructor<?> cons2 = birdClass.getConstructor(String.class);
Constructor<?> cons3 = birdClass.getConstructor(String.class, boolean.class);
}
There is no need for assertion since when a constructor with given parameter types in the given order does not exist, we will get a NoSuchMethodException and the test will automatically fail.
In the last test, we will see how to instantiate objects at runtime while supplying their parameters:
@Test
public void givenClass_whenInstantiatesObjectsAtRuntime_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Constructor<?> cons1 = birdClass.getConstructor();
Constructor<?> cons2 = birdClass.getConstructor(String.class);
Constructor<?> cons3 = birdClass.getConstructor(String.class,
boolean.class);
Bird bird1 = (Bird) cons1.newInstance();
Bird bird2 = (Bird) cons2.newInstance("Weaver bird");
Bird bird3 = (Bird) cons3.newInstance("dove", true);
assertEquals("bird", bird1.getName());
assertEquals("Weaver bird", bird2.getName());
assertEquals("dove", bird3.getName());
assertFalse(bird1.walks());
assertTrue(bird3.walks());
}
We instantiate class objects by calling the newInstance method of Constructor class and passing the required parameters in declared order. We then cast the result to the required type.
It's also possible to call the default constructor using the Class.newInstance() method. However, this method has been deprecated since Java 9, and we shouldn't use it in modern Java projects.
For bird1, we use the default constructor which from our Bird code, automatically sets the name to bird and we confirm that with a test.
We then instantiate bird2 with only a name and test as well, remember that when we don't set locomotion behavior as it defaults to false, as seen in the last two assertions.
7. Inspecting Fields
Previously, we only inspected the names of fields, in this section, we will show how to get and set their values at runtime.
There are two main methods used to inspect fields of a class at runtime: getFields() and getField(fieldName).
The getFields() method returns all accessible public fields of the class in question. It will return all the public fields in both the class and all superclasses.
For instance, when we call this method on the Bird class, we will only get the CATEGORY field of its superclass, Animal, since Bird itself does not declare any public fields:
@Test
public void givenClass_whenGetsPublicFields_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Field[] fields = birdClass.getFields();
assertEquals(1, fields.length);
assertEquals("CATEGORY", fields[0].getName());
}
This method also has a variant called getField which returns only one Field object by taking the name of the field:
@Test
public void givenClass_whenGetsPublicFieldByName_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Field field = birdClass.getField("CATEGORY");
assertEquals("CATEGORY", field.getName());
}
We are not able to access private fields declared in superclasses and not declared in the child class. This is why we are not able to access the name field.
However, we can inspect private fields declared in the class we are dealing with by calling the getDeclaredFields method:
@Test
public void givenClass_whenGetsDeclaredFields_thenCorrect(){
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Field[] fields = birdClass.getDeclaredFields();
assertEquals(1, fields.length);
assertEquals("walks", fields[0].getName());
}
We can also use its other variant in case we know the name of the field:
@Test
public void givenClass_whenGetsFieldsByName_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Field field = birdClass.getDeclaredField("walks");
assertEquals("walks", field.getName());
}
If we get the name of the field wrong or type in an in-existent field, we will get a NoSuchFieldException.
We get the field type as follows:
@Test
public void givenClassField_whenGetsType_thenCorrect() {
Field field = Class.forName("com.baeldung.reflection.Bird")
.getDeclaredField("walks");
Class<?> fieldClass = field.getType();
assertEquals("boolean", fieldClass.getSimpleName());
}
Next, we will look at how to access field values and modify them. To be able to get the value of a field, let alone setting it, we must first set it's accessible by calling setAccessible method on the Field object and pass boolean true to it:
@Test
public void givenClassField_whenSetsAndGetsValue_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Bird bird = (Bird) birdClass.getConstructor().newInstance();
Field field = birdClass.getDeclaredField("walks");
field.setAccessible(true);
assertFalse(field.getBoolean(bird));
assertFalse(bird.walks());
field.set(bird, true);
assertTrue(field.getBoolean(bird));
assertTrue(bird.walks());
}
In the above test, we ascertain that indeed the value of the walks field is false before setting it to true.
Notice how we use the Field object to set and get values by passing it the instance of the class we are dealing with and possibly the new value we want the field to have in that object.
One important thing to note about Field objects is that when it is declared as public static, then we don't need an instance of the class containing them, we can just pass null in its place and still obtain the default value of the field, like so:
@Test
public void givenClassField_whenGetsAndSetsWithNull_thenCorrect(){
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Field field = birdClass.getField("CATEGORY");
field.setAccessible(true);
assertEquals("domestic", field.get(null));
}8. Inspecting Methods
In a previous example, we used reflection only to inspect method names. However, Java reflection is more powerful than that.
With Java reflection, we can invoke methods at runtime and pass them their required parameters, just like we did for constructors. Similarly, we can also invoke overloaded methods by specifying parameter types of each.
Just like fields, there are two main methods that we use for retrieving class methods. The getMethods method returns an array of all public methods of the class and superclasses.
This means that with this method, we can get public methods of the java.lang.Object class like toString, hashCode, and notifyAll:
@Test
public void givenClass_whenGetsAllPublicMethods_thenCorrect(){
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Method[] methods = birdClass.getMethods();
List<String> methodNames = getMethodNames(methods);
assertTrue(methodNames.containsAll(Arrays
.asList("equals", "notifyAll", "hashCode",
"walks", "eats", "toString")));
}
To get only public methods of the class we are interested in, we have to use getDeclaredMethods method:
@Test
public void givenClass_whenGetsOnlyDeclaredMethods_thenCorrect(){
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
List<String> actualMethodNames
= getMethodNames(birdClass.getDeclaredMethods());
List<String> expectedMethodNames = Arrays
.asList("setWalks", "walks", "getSound", "eats");
assertEquals(expectedMethodNames.size(), actualMethodNames.size());
assertTrue(expectedMethodNames.containsAll(actualMethodNames));
assertTrue(actualMethodNames.containsAll(expectedMethodNames));
}
Each of these methods has the singular variation which returns a single Method object whose name we know:
@Test
public void givenMethodName_whenGetsMethod_thenCorrect() throws Exception {
Bird bird = new Bird();
Method walksMethod = bird.getClass().getDeclaredMethod("walks");
Method setWalksMethod = bird.getClass().getDeclaredMethod("setWalks", boolean.class);
assertTrue(walksMethod.canAccess(bird));
assertTrue(setWalksMethod.canAccess(bird));
}
Notice how we retrieve individual methods and specify what parameter types they take. Those that don't take parameter types are retrieved with an empty variable argument, leaving us with only a single argument, the method name.
Next, we will show how to invoke a method at runtime. We know by default that the walks attribute of the Bird class is false, we want to call its setWalks method and set it to true:
@Test
public void givenMethod_whenInvokes_thenCorrect() {
Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
Bird bird = (Bird) birdClass.getConstructor().newInstance();
Method setWalksMethod = birdClass.getDeclaredMethod("setWalks", boolean.class);
Method walksMethod = birdClass.getDeclaredMethod("walks");
boolean walks = (boolean) walksMethod.invoke(bird);
assertFalse(walks);
assertFalse(bird.walks());
setWalksMethod.invoke(bird, true);
boolean walks2 = (boolean) walksMethod.invoke(bird);
assertTrue(walks2);
assertTrue(bird.walks());
}
Notice how we first invoke the walks method and cast the return type to the appropriate data type and then check its value. We then later invoke the setWalks method to change that value and test again.
9. Conclusion
In this tutorial, we have covered the Java Reflection API and looked at
how to use it to inspect classes, interfaces, fields, and methods at
runtime without prior knowledge of their internals by compile time.
miércoles, 10 de febrero de 2021
Documentar una API Rest con OpenAPI 3 y Swagger UI o Swagger 2 con Springfox
OpenAPI 3 y Swagger UI: https://www.baeldung.com/spring-rest-openapi-documentation
Springfox implementation of the Swagger 2 specification: https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api
martes, 19 de enero de 2021
JPA - Anotaciones
A nivel de CLASE
@Entity: indica que la clase es una entidad de BBDD.
@MappedSuperClass: indica que las clases que hereden de ésta (subclases), también heredarán las anotaciones de sus propiedades. Y que NO se creará una tabla en la BBDD para ésta clase.
@Inheritance(strategy = InheritanceType.JOINED): igual que la anterior, pero para esta clase sí se crea una tabla en la BBDD.
@Table(name = "table_name"): especifica el nombre de la tabla relacionada con la entidad.
viernes, 10 de julio de 2020
Tutorial API REST con Java (JAX-RS) (sin Maven ni Spring Boot)
Para responder con JSON:
@GET
@Path("/json")
public Response getJsonResponse() {
Person person = new Person("Abhinayak", "Nepal");
return Response
.status(Response.Status.OK)
.entity(person)
.type(MediaType.APPLICATION_JSON)
.build();
}
lunes, 13 de abril de 2020
Unbound classpath container: JRE System Library
lunes, 30 de marzo de 2020
Java HashMap (Diccionarios)
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("valor1", 15);
map.put("valor2", 20);
map.put("valor3", 1000);
map.put("valor4", 1500);
map.put("valor5", 2);
int valor1 = map.get("valor1");
// para saber el número más alto se debe recorrer el mapa
int valorMax = -1;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
final int valorActual = entry.getValue();
if (valorActual > valorMax)
valorMax = valorActual;
}
System.out.println("Valor máximo: " + valorMax);
https://es.stackoverflow.com/questions/286092/diccionarios-en-java
https://docs.oracle.com/javase/tutorial/collections/interfaces/map.html
martes, 16 de julio de 2019
Cómo sincronizar un proyecto Java en Eclipse con un repositorio GitHub
miércoles, 13 de febrero de 2019
Java: Leer un fichero TXT y transformarlo en un JSON
jueves, 7 de febrero de 2019
Java: ordenar ArrayList de objetos por uno de sus atributos
this.getTimers().sort(Comparator.comparing(TimerBean::getDescripcion));
Siendo "Timers" nuestra lista de objetos "TimerBean" y "descripcion" el atributo por el que queremos ordenar la lista.
Comentar que también ordena por atributos de tipo numérico o fecha.



