Skip to content
Snippets Groups Projects
Commit 07a7d5a0 authored by jez04's avatar jez04
Browse files

feat: :tada: solution lab 10

parent df256e4a
No related merge requests found
......@@ -4,3 +4,8 @@ TikTokTornado;210;EASY
ScriptSensei;158;EASY
SnapMasteraaa;167000;null
ScriptSenseidddd;1580000;null
TikTokTornado;210;EASY
ScriptSensei;158000;MEDIUM
TikTokTornado;210000;EASY
TikTokTornado;210;EASY
ScriptSensei;158;EASY
package lab;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyEdit {
public boolean readOnly() default false;
public boolean visible() default true;
}
......@@ -8,7 +8,7 @@ import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lab.MyEdit;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
......@@ -31,11 +31,19 @@ public class Score {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@MyEdit(visible = false)
private Long id;
@MyEdit(readOnly = true)
private String name;
@MyEdit
private int points;
@Enumerated(EnumType.STRING)
@MyEdit
private Level level;
public String getVirtual(){
return "aaaa";
}
public static Score generate() {
......
......@@ -4,42 +4,25 @@ import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.HPos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import lab.Setup;
import lab.MyEdit;
import lab.data.Score;
import lab.game.Difficult;
import lombok.Setter;
/**
......@@ -75,9 +58,52 @@ public class EditController {
@FXML
void btnOkAction(ActionEvent event) {
//TODO: add code to read values from text fields
mainScreenController.updateData((Score)data);
try {
BeanInfo beanInfo = Introspector.getBeanInfo(data.getClass());
for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
try {
String name = propertyDescriptor.getName();
Field field = data.getClass().getDeclaredField(name);
MyEdit myEdit = field.getAnnotation(MyEdit.class);
if(myEdit == null || !myEdit.visible() || myEdit.readOnly()) {
continue;
}
TextField textField = nameToTextField.get(name);
String stringValue = textField.getText();
Object value = null;
if (propertyDescriptor.getPropertyType() == String.class) {
value = stringValue;
} else if (stringValue == null || stringValue.isBlank()) {
value = null;
} else if (propertyDescriptor.getPropertyType() == Integer.class
|| propertyDescriptor.getPropertyType() == int.class) {
value = Integer.parseInt(stringValue);
} else if (propertyDescriptor.getPropertyType() == Long.class
|| propertyDescriptor.getPropertyType() == long.class) {
value = Long.parseLong(stringValue);
} else if (propertyDescriptor.getPropertyType() == Double.class
|| propertyDescriptor.getPropertyType() == double.class) {
value = Double.parseDouble(stringValue);
} else if (propertyDescriptor.getPropertyType().isEnum()) {
for (Object enumConstant : propertyDescriptor.getPropertyType().getEnumConstants()) {
if (enumConstant.toString().equalsIgnoreCase(stringValue)) {
value = enumConstant;
break;
}
}
}
if (propertyDescriptor.getWriteMethod() != null) {
propertyDescriptor.getWriteMethod().invoke(data, value);
}
} catch (NoSuchFieldException e) {
log.warn("property {} has no field", propertyDescriptor.getName());
}
}
} catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
log.error(e);
}
mainScreenController.updateData((Score) data);
stage.hide();
}
......@@ -93,15 +119,41 @@ public class EditController {
public void setObjectToEdit(Object data) {
this.data = data;
log.info("data set {}", data);
log.info("data set {}", data);
content.getChildren().clear();
//TODO: code to detect properties and add rows to dialog
ResourceBundle msg = ResourceBundle.getBundle("msg");
try {
BeanInfo beanInfo = Introspector.getBeanInfo(data.getClass());
int row = 0;
for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors()) {
try {
Field field = data.getClass().getDeclaredField(propertyDescriptor.getName());
MyEdit myEdit = field.getAnnotation(MyEdit.class);
if (myEdit == null) {
continue;
}
if (!myEdit.visible()) {
continue;
}
String name = propertyDescriptor.getName();
Object value = propertyDescriptor.getReadMethod().invoke(data);
String localizedName = msg.getString(String.format("%s.%s", data.getClass().getSimpleName(), field.getName()));
addDialogRow(row, name, localizedName, value != null ? value.toString() : "", !myEdit.readOnly());
row++;
} catch (NoSuchFieldException e) {
log.warn("property '{}' has no field in class '{}'", propertyDescriptor.getName(), data.getClass().getCanonicalName());
}
}
} catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
log.error(e);
}
}
private void addDialogRow(int rowNumber, String name, String descriptionName, String stringValue) {
private void addDialogRow(int rowNumber, String name, String descriptionName, String stringValue,
boolean editable) {
Label label = new Label(descriptionName);
TextField textField = new TextField(stringValue);
textField.setEditable(editable);
nameToTextField.put(name, textField);
content.addRow(rowNumber, label, textField);
GridPane.setHalignment(label, HPos.RIGHT);
......
Score.id = id
Score.level = level
Score.name = name
Score.points = points
Score.id = Jednozna\u010Dn\u00FD identifik\u00E1tor
Score.level = Obt\u00ED\u017Enost
Score.name = Jm\u00E9no
Score.points = Body
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
Score.id = Jedine\u010Dn\u00FD identifik\u00E1tor
Score.name = N\u00E1zev
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
Score.id = Unique identificator
Score.level = Level
Score.name = Name
Score.points = Points
......@@ -2,176 +2,40 @@ package jez04.structure.test;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import cz.vsb.fei.kelvin.unittest.ProjectContains;
import cz.vsb.fei.kelvin.unittest.StructureHelper;
import cz.vsb.fei.kelvin.unittest.TextFileContains;
import cz.vsb.fei.kelvin.unittest.XmlFileContains;
import lab.data.Level;
import lab.data.Score;
import lab.storage.JpaConnector;
class ClassStructureTest {
StructureHelper helper = StructureHelper.getInstance(ClassStructureTest.class);
@Test
void jakartaAndHibernateAsDependencyTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'jakarta.persistence-api']"));
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'hibernate-core']"));
// @formatter:off
@ParameterizedTest
@CsvSource({
"Score.java,@MyEdit,4",
"EditController.java,Introspector.getBeanInfo,1",
"EditController.java,BeanInfo,1",
"EditController.java,PropertyDescriptor,1",
"EditController.java,getDeclaredField,1",
"EditController.java,getAnnotation,1",
"EditController.java,\\.readOnly\\(\\),1",
"EditController.java,\\.visible\\(\\),1",
"MyEdit.java,@interface,1",
"MyEdit.java,@Retention,1",
"MyEdit.java,RetentionPolicy\\.RUNTIME,1",
"MyEdit.java,readOnly\\(\\),1",
"MyEdit.java,visible\\(\\),1",
"msg(_.*)?\\.properties,points,2",
})
// @formatter:on
void anotaceTest(String file, String annotation, int count) throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains(file, annotation).count(count).useRegExpForName(true));
}
@Test
void jakartaInModulInfoTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("module-info.java", "jakarta.persistence;"));
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("module-info.java", "opens\\slab.data;"));
}
@Test
void pesistenceXmlTest() throws URISyntaxException {
ProjectContains projectContains = new ProjectContains("persistence.xml");
assertThat(TextFileContains.getProjectRoot(getClass()), projectContains);
assertThat(projectContains.getFoundFiles(), Matchers.not(Matchers.hasSize(0)));
Path persistenceXml = projectContains.getFoundFiles().getFirst();
assertThat(persistenceXml.toAbsolutePath().toString(),
Matchers.endsWith(Paths.get("resources", "META-INF", "persistence.xml").toString()));
}
@Test
void useEnumeratedTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains("Score.java", "@Enumerated\\(\\s*EnumType.STRING\\s*\\)"));
}
@TestMethodOrder(OrderAnnotation.class)
@Nested
class JpaConnectorTests {
private Score template = new Score(null, "Tester", 100, Level.EASY);
private JpaConnector connector;
@BeforeEach
void init() {
connector = new JpaConnector();
}
@AfterEach
void cleanUp() {
connector.stop();
}
boolean same(Score s1, Score s2) {
return s1.getLevel() == s2.getLevel() && s1.getPoints() == s2.getPoints()
&& Objects.equals(s1.getName(), s2.getName());
}
@Test
@Order(100)
void jpaScoreInsertTest() {
Score savedScore = connector.save(template);
assertThat(savedScore.getId(), Matchers.notNullValue());
}
@Test
@Order(200)
void jpaScoreReadTest() {
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
}
@Test
@Order(250)
void jpaReadSortedTest() {
for (int i = 0; i < 20; i++) {
connector.save(template.toBuilder().points(i).build());
}
List<Score> result = connector.getFirstTen();
assertThat(result, Matchers.hasSize(10));
for (int i = 0; i < result.size()-1; i++) {
assertThat(result.get(i).getPoints(), Matchers.greaterThanOrEqualTo(result.get(i+1).getPoints()));
}
}
@Test
@Order(300)
void jpaScoreModifyTest() {
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
List<Long> savedIds = savedScores.stream().map(Score::getId).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
for (Score score : savedScores) {
score.setLevel(Level.HARD);
connector.save(score);
}
List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList();
assertThat(modifiedScores, Matchers.not(Matchers.hasSize(0)));
List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(originalDataScores, Matchers.hasSize(0));
}
@Test
@Order(400)
void jpaScoreDeleteTest() {
template.setLevel(Level.HARD);
List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
List<Long> savedIds = savedScores.stream().map(Score::getId).toList();
assertThat(savedScores, Matchers.not(Matchers.hasSize(0)));
connector.delete(savedScores);
List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList();
assertThat(modifiedScores, Matchers.hasSize(0));
List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList();
assertThat(originalDataScores, Matchers.hasSize(0));
}
@Test
@Order(400)
void jpaMergeTest() {
connector.save(template);
connector.find(template.getId());
Score copy = template.toBuilder().points(500).build();
Score result = connector.save(copy);
assertThat(result, Matchers.not(Matchers.sameInstance(copy)));
}
@Test
@Order(500)
void jpamodifyNoPersistNoMergeTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException {
template.setName("aaa");
connector.save(template);
connector.modifyNoPersistOrMerge(template.getId(), score -> score.setName("ok"));
Object em = connector.getEntityManager();
em.getClass().getMethod("clear").invoke(em);
assertThat(connector.find(template.getId()).getName(), Matchers.equalTo("ok"));
TextFileContains textFileContains = new TextFileContains("JpaConnector.java",
"void\\s+modifyNoPersistOrMerge[\\s\\S]*}").multiline(true);
assertThat(TextFileContains.getProjectRoot(ClassStructureTest.class), textFileContains);
Path score = textFileContains.getFoundFiles().getFirst();
String src = Files.readString(score);
String method = Pattern.compile("void\\s+modifyNoPersistOrMerge[\\s\\S]*}").matcher(src).results().findFirst().get().group();
assertThat(method, Matchers.not(Matchers.containsString("persist")));
assertThat(method, Matchers.not(Matchers.containsString("merge")));
}
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment